<!DOCTYPE html>
<html lang="en" dir="ltr">

<head prefix="og: http://ogp.me/ns#">
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Dartlang – Yang Blog</title>
    


  
  <script defer src="/js/fuse.min.32195737929df2c8096e855a5789cbb3f1331224d9169e8705493e7008f47df8.js"></script>



<script src="/js/enquire.min.dfb99dee1e029d51d6cfb672d847929890b1585402de17f5ed092edd72a688b4.js"></script>

<script defer src="/js/lazysizes.min.fb649fcae62177dfe63e67081ddceb830b5ce1f05a4184e9bbb7d87ac4b8f4e5.js"></script>

<script defer src="/js/helper/getParents.min.ccd45f158c1b17849307ba913a72beac239c410f2b6e648496a79842da84e55b.js"></script>

<script defer src="/js/helper/fadeinout.min.1d13d3e810c3940e80cbba6216a1c76fbf42b5431fc83537ea6997863802362b.js"></script>

<script defer src="/js/helper/closest.min.js"></script>
  
<script>
  "use strict";

  
  
  if (window.NodeList && !NodeList.prototype.forEach) {
    NodeList.prototype.forEach = Array.prototype.forEach;
  }

  
  if (!String.prototype.includes) {
    String.prototype.includes = function (search, start) {
      'use strict';

      if (search instanceof RegExp) {
        throw TypeError('first argument must not be a RegExp');
      }
      if (start === undefined) { start = 0; }
      return this.indexOf(search, start) !== -1;
    };
  }

  
  Document.prototype.append = Element.prototype.append = function append() {
    this.appendChild(_mutation(arguments));
  };
  function _mutation(nodes) {
    if (!nodes.length) {
      throw new Error('DOM Exception 8');
    } else if (nodes.length === 1) {
      return typeof nodes[0] === 'string' ? document.createTextNode(nodes[0]) : nodes[0];
    } else {
      var
      fragment = document.createDocumentFragment(),
      length = nodes.length,
      index = -1,
      node;

      while (++index < length) {
        node = nodes[index];

        fragment.appendChild(typeof node === 'string' ? document.createTextNode(node) : node);
      }

      return fragment;
    }
  }

  
  if (!String.prototype.startsWith) {
    String.prototype.startsWith = function (searchString, position) {
      position = position || 0;
      return this.indexOf(searchString, position) === position;
    };
  }
  


  document.addEventListener('DOMContentLoaded', function () {
    
    var navCollapseBtn = document.querySelector('.navbar__burger');
    navCollapseBtn ? navCollapseBtn.addEventListener('click', function (e) {
      var navCollapse = document.querySelector('.navbarm__collapse');

      if (navCollapse) {
        var dataOpen = navCollapse.getAttribute('data-open');

        if (dataOpen === 'true') {
          navCollapse.setAttribute('data-open', 'false');
          navCollapse.style.maxHeight = 0;
          navCollapseBtn.classList.remove('is-active');
        } else {
          navCollapse.setAttribute('data-open', 'true');
          navCollapse.style.maxHeight = navCollapse.scrollHeight + "px";
          navCollapseBtn.classList.add('is-active');
        }
      }
    }) : null;
    


    
    var tables = document.querySelectorAll('.single__contents > table');
    for (let i = 0; i < tables.length; i++) {
      var table = tables[i];
      var wrapper = document.createElement('div');
      wrapper.className = 'table-wrapper';
      table.parentElement.replaceChild(wrapper, table);
      wrapper.appendChild(table);
    }
    


    
    var footNoteRefs = document.querySelectorAll('.footnote-ref');
    var footNoteBackRefs = document.querySelectorAll('.footnote-backref');

    footNoteRefs ? 
    footNoteRefs.forEach(function(elem, idx) {
      elem.onmouseenter = function () {
        if (navbar.classList.contains('scrolling')) {
          navbar.classList.remove('scrolling');
        }
      }

      elem.onmouseleave = function () {
        if (!navbar.classList.contains('scrolling')) {
          setTimeout(function () {
            navbar.classList.add('scrolling');
          }, 100);
        }
      }

      elem.onclick = function () {
        if (!navbar.classList.contains('scrolling')) {
          navbar.classList.remove('navbar--show');
          navbar.classList.remove('navbar--hide');
          navbar.classList.add('navbar--hide');
        }
      }
    }) : null;

    footNoteBackRefs ? 
    footNoteBackRefs.forEach(function(elem, idx) {
      elem.onmouseenter = function () {
        if (navbar.classList.contains('scrolling')) {
          navbar.classList.remove('scrolling');
        }
      }

      elem.onmouseleave = function () {
        if (!navbar.classList.contains('scrolling')) {
          setTimeout(function() {
            navbar.classList.add('scrolling');
          }, 100);
        }
      }

      elem.onclick = function () {
        if (!navbar.classList.contains('scrolling')) {
          navbar.classList.remove('navbar--show');
          navbar.classList.remove('navbar--hide');
          navbar.classList.add('navbar--hide');
        }
      }
    }) : null;
    


    
    var summaryContainer = document.querySelector('.summary__container');
    var searchResult = document.querySelector('.search-result');
    var searchResultCloseBtn = document.querySelector('.search-result__close');
    searchResultCloseBtn ? searchResultCloseBtn.addEventListener('click', function (e) {
      searchResult.setAttribute('data-display', 'none');
      summaryContainer.setAttribute('data-display', 'block');
    }) : null;
    


    
    document.querySelectorAll('.tab') ? 
    document.querySelectorAll('.tab').forEach(function(elem, idx) {
      var containerId = elem.getAttribute('id');
      var containerElem = elem;
      var tabLinks = elem.querySelectorAll('.tab__link');
      var tabContents = elem.querySelectorAll('.tab__content');
      var ids = [];

      tabLinks && tabLinks.length > 0 ?
      tabLinks.forEach(function(link, index, self) {
        link.onclick = function(e) {
          for (var i = 0; i < self.length; i++) {
            if (index === parseInt(i, 10)) {
              if (!self[i].classList.contains('active')) {
                self[i].classList.add('active');
                tabContents[i].style.display = 'block';
              }
            } else {
              self[i].classList.remove('active');
              tabContents[i].style.display = 'none';
            }
          }
        }
      }) : null;
    }) : null;
    


    
    document.querySelectorAll('.codetab') ? 
    document.querySelectorAll('.codetab').forEach(function(elem, idx) {
      var containerId = elem.getAttribute('id');
      var containerElem = elem;
      var codetabLinks = elem.querySelectorAll('.codetab__link');
      var codetabContents = elem.querySelectorAll('.codetab__content');
      var ids = [];

      codetabLinks && codetabLinks.length > 0 ?
      codetabLinks.forEach(function(link, index, self) {
        link.onclick = function(e) {
          for (var i = 0; i < self.length; i++) {
            if (index === parseInt(i, 10)) {
              if (!self[i].classList.contains('active')) {
                self[i].classList.add('active');
                codetabContents[i].style.display = 'block';
              }
            } else {
              self[i].classList.remove('active');
              codetabContents[i].style.display = 'none';
            }
          }
        }
      }) : null;
    }) : null;
    


    
    var gttBtn = document.getElementById("gtt");
    gttBtn.style.display = "none";
    gttBtn.addEventListener('click', function () {
      if (window.document.documentMode) {
        document.documentElement.scrollTop = 0;
      } else {
        scrollToTop(250);
      }
    });

    function scrollToTop(scrollDuration) {
      var scrollStep = -window.scrollY / (scrollDuration / 15);
      var scrollInterval = setInterval(function () {
        if (window.scrollY != 0) {
          window.scrollBy(0, scrollStep);
        }
        else clearInterval(scrollInterval);
      }, 15);
    }

    var scrollFunction = function () {
      if (document.body.scrollTop > 250 || document.documentElement.scrollTop > 250) {
        gttBtn.style.display = "block";
      } else {
        gttBtn.style.display = "none";
      }
    }
    


    
    var expandBtn = document.querySelectorAll('.expand__button');

    for (let i = 0; i < expandBtn.length; i++) {
      expandBtn[i].addEventListener("click", function () {
        var content = this.nextElementSibling;
        if (content.style.maxHeight) {
          content.style.maxHeight = null;
          this.querySelector('svg').classList.add('expand-icon__right');
          this.querySelector('svg').classList.remove('expand-icon__down');
        } else {
          content.style.maxHeight = content.scrollHeight + "px";
          this.querySelector('svg').classList.remove('expand-icon__right');
          this.querySelector('svg').classList.add('expand-icon__down');
        }
      });
    }
    


    
    var lastScrollTop = window.pageYOffset || document.documentElement.scrollTop;
    var tocElem = document.querySelector('.toc');
    var tableOfContentsElem = tocElem ? tocElem.querySelector('#TableOfContents') : null;
    var toggleTocElem = document.getElementById('toggle-toc');
    var singleContentsElem = document.querySelector('.single__contents');
    var navbar = document.querySelector('.navbar');
    var tocFlexbox = document.querySelector('.toc__flexbox');
    var tocFlexboxOuter = document.querySelector('.toc__flexbox--outer');
    var expandContents = document.querySelectorAll('.expand__content');
    var boxContents = document.querySelectorAll('.box');
    var notAllowedTitleIds = null;

    
    var tocFolding = JSON.parse("false");
    
    var tocLevels = JSON.parse("[\"h2\",\"h3\",\"h4\",\"h5\",\"h6\"]");
    
    if (tocLevels) {
      tocLevels = tocLevels.toString();
    } else {
      tocLevels = "h1, h2, h3, h4, h5, h6";
    }

    
    singleContentsElem && singleContentsElem.querySelectorAll(".tab") ?
    singleContentsElem.querySelectorAll(".tab").forEach(function (elem) {
      elem.querySelectorAll(tocLevels).forEach(function (element) {
        notAllowedTitleIds = Array.isArray(notAllowedTitleIds) ?
          notAllowedTitleIds.concat(element.getAttribute('id')) :
          [element.getAttribute('id')];
      });
    }) : null;

    
    expandContents ? expandContents.forEach(function(elem) {
      elem.querySelectorAll(tocLevels).forEach(function (element) {
        notAllowedTitleIds = Array.isArray(notAllowedTitleIds) ?
          notAllowedTitleIds.concat(element.getAttribute('id')) :
          [element.getAttribute('id')];
      });
    }) : null;

    
    boxContents ? boxContents.forEach(function(elem) {
      elem.querySelectorAll(tocLevels).forEach(function (element) {
        notAllowedTitleIds = Array.isArray(notAllowedTitleIds) ?
          notAllowedTitleIds.concat(element.getAttribute('id')) :
          [element.getAttribute('id')];
      });
    }) : null;

    
    window.onscroll = function () {
      scrollFunction();
      
      var st = window.pageYOffset || document.documentElement.scrollTop;
      if (st > lastScrollTop) { 
        if (st < 250) {
          gttBtn.style.display = "none";
        } else {
          gttBtn.style.display = "block";
        }

        if (st < 45) {
          return null;
        }

        if (navbar.classList.contains('scrolling')) {
          if (!navbar.classList.contains('navbar--hide')) {
            navbar.classList.add('navbar--hide');
          } else if (navbar.classList.contains('navbar--show')) {
            navbar.classList.remove('navbar--show');
          }
        }

        if (singleContentsElem) {
          if (singleContentsElem.querySelectorAll(tocLevels).length > 0) {
            singleContentsElem.querySelectorAll(tocLevels).forEach(function (elem) {
              if (toggleTocElem && !toggleTocElem.checked) {
                return null;
              }

              if (notAllowedTitleIds && notAllowedTitleIds.includes(elem.getAttribute('id'))) {
                return null;
              }
              
              if (document.documentElement.scrollTop >= elem.offsetTop) {
                if (tableOfContentsElem) {
                  var id = elem.getAttribute('id');
                  tocElem.querySelectorAll('a').forEach(function (elem) {
                    elem.classList.remove('active');
                  });
                  tocElem.querySelector('a[href="#' + id + '"]') ?
                    tocElem.querySelector('a[href="#' + id + '"]').classList.add('active') : null;

                  if (false === tocFolding) {
                    
                  } else {
                    tableOfContentsElem.querySelectorAll('ul') ?
                      tableOfContentsElem.querySelectorAll('ul').forEach(function (rootUl) {
                        rootUl.querySelectorAll('li').forEach(function (liElem) {
                          liElem.querySelectorAll('ul').forEach(function (ulElem) {
                            ulElem.style.display = 'none';
                          });
                        });
                      }) : null;
                  }

                  var curElem = tableOfContentsElem.querySelector("[href='#" + id + "']");
                  if (curElem && curElem.nextElementSibling) {
                    curElem.nextElementSibling.style.display = 'block';
                  }
                  getParents(curElem, 'ul') ?
                    getParents(curElem, 'ul').forEach(function (elem) {
                      elem.style.display = 'block';
                    }) : null;
                }
              }
            });
          } else {
            if (tocFlexbox) {
              tocFlexbox.setAttribute('data-position', '');
              if (!tocFlexbox.classList.contains('hide')) {
                tocFlexbox.classList.add('hide');
              }
            }
            if (tocFlexboxOuter) {
              tocFlexboxOuter.setAttribute('data-position', '');
              if (!tocFlexboxOuter.classList.contains('hide')) {
                tocFlexboxOuter.classList.add('hide');
              }
            }
          }
        }
      } else { 
        if (st < 250) {
          gttBtn.style.display = "none";
        }

        if (navbar.classList.contains('scrolling')) {
          if (navbar.classList.contains('navbar--hide')) {
            navbar.classList.remove('navbar--hide');
          } else if (!navbar.classList.contains('navbar--show')) {
            navbar.classList.add('navbar--show');
          }
        }

        if (singleContentsElem) {
          if (singleContentsElem.querySelectorAll(tocLevels).length > 0) {
            singleContentsElem.querySelectorAll(tocLevels).forEach(function (elem) {
              if (toggleTocElem && !toggleTocElem.checked) {
                return null;
              }
              
              if (notAllowedTitleIds && notAllowedTitleIds.includes(elem.getAttribute('id'))) {
                return null;
              }

              if (document.documentElement.scrollTop >= elem.offsetTop) {
                if (tableOfContentsElem) {
                  var id = elem.getAttribute('id');
                  tocElem.querySelectorAll('a').forEach(function (elem) {
                    elem.classList.remove('active');
                  });
                  tocElem.querySelector('a[href="#' + id + '"]') ?
                    tocElem.querySelector('a[href="#' + id + '"]').classList.add('active') : null;

                  if (false === tocFolding) {
                    
                  } else {
                    tableOfContentsElem.querySelectorAll('ul') ?
                      tableOfContentsElem.querySelectorAll('ul').forEach(function (rootUl) {
                        rootUl.querySelectorAll('li').forEach(function (liElem) {
                          liElem.querySelectorAll('ul').forEach(function (ulElem) {
                            ulElem.style.display = 'none';
                          });
                        });
                      }) : null;
                  }

                  var curElem = tableOfContentsElem.querySelector("[href='#" + id + "']");
                  if (curElem && curElem.nextElementSibling) {
                    curElem.nextElementSibling.style.display = 'block';
                  }
                  getParents(curElem, 'ul') ?
                    getParents(curElem, 'ul').forEach(function (elem) {
                      elem.style.display = 'block';
                    }) : null;
                }
              }
            });
          } else {
            if (tocFlexbox && !tocFlexbox.classList.contains('hide')) {
              tocFlexbox.classList.add('hide');
            }
            if (tocFlexboxOuter && !tocFlexboxOuter.classList.contains('hide')) {
              tocFlexboxOuter.classList.add('hide');
            }
          }
          
        }

        if (tableOfContentsElem && document.documentElement.scrollTop < 250) {
          if (false === tocFolding) {

          } else {
            tableOfContentsElem.querySelector('ul') ?
              tableOfContentsElem.querySelector('ul').querySelectorAll('li').forEach(function (liElem) {
                liElem.querySelectorAll('ul').forEach(function (ulElem) {
                  ulElem.style.display = 'none';
                });
              }) : null;
          }
        }
      }
      lastScrollTop = st <= 0 ? 0 : st;
    };
  


  
    var localTheme = localStorage.getItem('theme');
    var rootEleme = document.getElementById('root');
    var selectThemeElem = document.querySelectorAll('.select-theme');
    var selectThemeItemElem = document.querySelectorAll('.select-theme__item');
    
    
    var skinDarkCode = JSON.parse("\"dark\"");
    
    var skinLightCode = JSON.parse("\"light\"");
    
    var skinHackerCode = JSON.parse("\"hacker\"");
    
    var skinSolarizedCode = JSON.parse("\"solarized\"");
    
    var skinKimbieCode = JSON.parse("\"kimbie\"");

    var setMetaColor = function(themeColor) {
      var metaMsapplicationTileColor = document.getElementsByName('msapplication-TileColor')[0];
      var metaThemeColor = document.getElementsByName('theme-color')[0];
      var metaMsapplicationNavbuttonColor = document.getElementsByName('msapplication-navbutton-color')[0];
      var metaAppleMobileWebAappStatusBarStyle = document.getElementsByName('apple-mobile-web-app-status-bar-style')[0];

      if (themeColor.includes('dark')) {
        metaMsapplicationTileColor.setAttribute('content', '#fcfcfa');
        metaThemeColor.setAttribute('content', '#403E41');
        metaMsapplicationNavbuttonColor.setAttribute('content', '#403E41');
        metaAppleMobileWebAappStatusBarStyle.setAttribute('content', '#403E41');
      } else if (themeColor.includes('light')) {
        metaMsapplicationTileColor.setAttribute('content', '#555');
        metaThemeColor.setAttribute('content', '#eee');
        metaMsapplicationNavbuttonColor.setAttribute('content', '#eee');
        metaAppleMobileWebAappStatusBarStyle.setAttribute('content', '#eee');
      } else if (themeColor.includes('hacker')) {
        metaMsapplicationTileColor.setAttribute('content', '#e3cd26');
        metaThemeColor.setAttribute('content', '#252526');
        metaMsapplicationNavbuttonColor.setAttribute('content', '#252526');
        metaAppleMobileWebAappStatusBarStyle.setAttribute('content', '#252526');
      } else if (themeColor.includes('solarized')) {
        metaMsapplicationTileColor.setAttribute('content', '#d3af86');
        metaThemeColor.setAttribute('content', '#51412c');
        metaMsapplicationNavbuttonColor.setAttribute('content', '#51412c');
        metaAppleMobileWebAappStatusBarStyle.setAttribute('content', '#51412c');
      } else if (themeColor.includes('kimbie')) {
        metaMsapplicationTileColor.setAttribute('content', '#586e75');
        metaThemeColor.setAttribute('content', '#eee8d5');
        metaMsapplicationNavbuttonColor.setAttribute('content', '#eee8d5');
        metaAppleMobileWebAappStatusBarStyle.setAttribute('content', '#eee8d5');
      }
    }

    var parseSkinCode = function(themeText) {
      if (themeText === skinDarkCode) {
        return 'dark';
      } else if (themeText === skinLightCode) {
        return 'light';
      } else if (themeText === skinHackerCode) {
        return 'hacker';
      } else if (themeText === skinSolarizedCode) {
        return 'solarized';
      } else if (themeText === skinKimbieCode) {
        return 'kimbie';
      }
    }
    
    if (localTheme) {
      selectThemeItemElem ? 
      selectThemeItemElem.forEach(function (elem) {
        if (elem.text.trim() === localTheme) {
          elem.classList.add('is-active');
        } else {
          elem.classList.remove('is-active');
        }
      }) : null;

      setMetaColor(localTheme);
    } else {
      setMetaColor(rootEleme.className);
    }

    selectThemeItemElem ? 
    selectThemeItemElem.forEach(function (v, i) {
      v.addEventListener('click', function (e) {
        var selectedThemeVariant = parseSkinCode(e.target.text.trim());
        localStorage.setItem('theme', selectedThemeVariant);
        setMetaColor(selectedThemeVariant);

        rootEleme.removeAttribute('class');
        rootEleme.classList.add('theme__' + selectedThemeVariant);
        selectThemeElem.forEach(function(rootElem) {
          rootElem.querySelectorAll('a').forEach(function (elem) {
            if (elem.classList) {
              if (elem.text.trim() === selectedThemeVariant) {
                if (!elem.classList.contains('is-active')) {
                  elem.classList.add('is-active');
                }
              } else {
                if (elem.classList.contains('is-active')) {
                  elem.classList.remove('is-active');
                }
              }
            }
          });
        });

        if (window.mermaid) {
          if (selectedThemeVariant === "dark" || selectedThemeVariant === "hacker") {
            mermaid.initialize({ theme: 'dark' });
            location.reload();
          } else {
            mermaid.initialize({ theme: 'default' });
            location.reload();
          }
        }

        var utterances = document.getElementById('utterances');
        if (utterances) {
          utterances.querySelector('iframe').contentWindow.postMessage({
            type: 'set-theme',
            theme: selectedThemeVariant === "dark" || selectedThemeVariant === "hacker" ? 'photon-dark' : selectedThemeVariant === 'kimbie' ? 'github-dark-orange' : 'github-light',
          }, 'https://utteranc.es');
        }

        var twitterCards = document.querySelectorAll('.twitter-timeline');
        if (twitterCards) {
          window.postMessage({
            type: 'set-twitter-theme',
            theme: selectedThemeVariant === 'light' || selectedThemeVariant === 'solarized' ? 'light' : 'dark',
          });
        }
      });
    }) : null;
  


  
    
    var baseurl = JSON.parse("\"https://jiyang.site/\"");
    
    var permalink = JSON.parse("\"https://jiyang.site/posts/2019-03-01-dartlang/\"");
    
    var langprefix = JSON.parse("\"\"");
    var searchResults = null;
    var searchMenu = null;
    var searchText = null;
    
    
    var enableSearch = JSON.parse("true");
    
    var enableSearchHighlight = JSON.parse("true");
    
    var searchResultPosition = JSON.parse("null");
    
    var sectionType = JSON.parse("\"posts\"");
    
    var kind = JSON.parse("\"page\"");
    
    var fuse = null;

    if (enableSearch) {
      (function initFuse() {
        var xhr = new XMLHttpRequest();
        if (sectionType === "publication" && kind !== "page") {
          xhr.open('GET', permalink + "index.json");
        } else {
          xhr.open('GET', baseurl + langprefix + "/index.json");
        }
        
        xhr.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
        xhr.onload = function () {
          if (xhr.status === 200) {
            fuse = new Fuse(JSON.parse(xhr.response.toString('utf-8')), {
              keys: sectionType.includes('publication') ? ['title', 'abstract'] : ['title', 'description', 'content'],
              includeMatches: enableSearchHighlight,
              shouldSort: true, 
              threshold: 0.4, 
              location: 0, 
              distance: 100, 
              maxPatternLength: 32,
              minMatchCharLength: 1,
              isCaseSensitive: false, 
              findAllMatches: false, 
              useExtendedSearch: false, 
            });
            window.fuse = fuse;
          }
          else {
            console.error('[' + xhr.status + ']Error:', xhr.statusText);
          }
        };
        xhr.send();
      })();
    }

    function makeLi(ulElem, obj) {
      var li = document.createElement('li');
      li.className = 'search-result__item';
      
      var a = document.createElement('a');
      a.innerHTML = obj.item.title;
      a.setAttribute('class', 'search-result__item--title');
      a.setAttribute('href', obj.item.permalink);

      var descDiv = document.createElement('div');
      descDiv.setAttribute('class', 'search-result__item--desc');
      if (obj.item.description) {
        descDiv.innerHTML = obj.item.description;
      } else if (obj.item.content) {
        descDiv.innerHTML = obj.item.content.substring(0, 225);
      }
      
      li.appendChild(a);
      li.appendChild(descDiv);
      ulElem.appendChild(li);
    }

    function makeHighlightLi(ulElem, obj) {
      var li = document.createElement('li');
      li.className = 'search-result__item';
      var descDiv = null;

      var a = document.createElement('a');
      a.innerHTML = obj.item.title;
      a.setAttribute('class', 'search-result__item--title');
      a.setAttribute('href', obj.item.uri);

      if (obj.matches && obj.matches.length) {
        for (var i = 0; i < obj.matches.length; i++) {
          if ('title' === obj.matches[i].key) {
            a = document.createElement('a');
            a.innerHTML = generateHighlightedText(obj.matches[i].value, obj.matches[i].indices);
            a.setAttribute('class', 'search-result__item--title');
            a.setAttribute('href', obj.item.uri);
          }
          
          if ('description' === obj.matches[i].key) {
            descDiv = document.createElement('div');
            descDiv.setAttribute('class', 'search-result__item--desc');
            descDiv.innerHTML = generateHighlightedText(obj.item.description, obj.matches[i].indices);
          } else if ('content' === obj.matches[i].key) {
            if (!descDiv) {
              descDiv = document.createElement('div');
              descDiv.setAttribute('class', 'search-result__item--desc');
              descDiv.innerHTML = generateHighlightedText(obj.item.content.substring(0, 150), obj.matches[i].indices);
            }
          } else {
            if (obj.item.description) {
              descDiv = document.createElement('div');
              descDiv.setAttribute('class', 'search-result__item--desc');
              descDiv.innerHTML = obj.item.description;
            } else {
              descDiv = document.createElement('div');
              descDiv.setAttribute('class', 'search-result__item--desc');
              descDiv.innerHTML = obj.item.content.substring(0, 150);
            }
          }
        }

        li.appendChild(a);
        if (descDiv) {
          li.appendChild(descDiv);
        }
        if (li) {
          ulElem.appendChild(li);
        }
      }
    }

    function renderSearchResultsSide(searchText, results) {
      searchResults = document.getElementById('search-results');
      searchMenu = document.getElementById('search-menu');
      searchResults.setAttribute('class', 'dropdown is-active');
      
      var ul = document.createElement('ul');
      ul.setAttribute('class', 'dropdown-content search-content');

      if (results.length) {
        results.forEach(function (result) {
          var li = document.createElement('li');
          var a = document.createElement('a');
          a.setAttribute('href', result.uri);
          a.setAttribute('class', 'dropdown-item');
          a.appendChild(li);

          var titleDiv = document.createElement('div');
          titleDiv.innerHTML = result.title;
          titleDiv.setAttribute('class', 'menu-item__title');

          var descDiv = document.createElement('div');
          descDiv.setAttribute('class', 'menu-item__desc');
          if (result.description) {
            descDiv.innerHTML = result.description;
          } else if (result.content) {
            descDiv.innerHTML = result.content.substring(0, 150);
          }

          li.appendChild(titleDiv);
          li.appendChild(descDiv);
          ul.appendChild(a);
        });
      } else {
        var li = document.createElement('li');
        li.setAttribute('class', 'dropdown-item');
        li.innerText = 'No results found';
        ul.appendChild(li);
      }

      while (searchMenu.hasChildNodes()) {
        searchMenu.removeChild(
          searchMenu.lastChild
        );
      }
      
      searchMenu.appendChild(ul);
    }

    function renderSearchHighlightResultsSide(searchText, results) {
      searchResults = document.getElementById('search-results');
      searchMenu = document.getElementById('search-menu');
      searchResults.setAttribute('class', 'dropdown is-active');

      var ul = document.createElement('ul');
      ul.setAttribute('class', 'dropdown-content search-content');

      if (results.length) {
        results.forEach(function (result) {
          var li = document.createElement('li');
          var a = document.createElement('a');
          var descDiv = null;

          a.setAttribute('href', result.item.uri);
          a.setAttribute('class', 'dropdown-item');
          a.appendChild(li);

          var titleDiv = document.createElement('div');
          titleDiv.innerHTML = result.item.title;
          titleDiv.setAttribute('class', 'menu-item__title');
          
          if (result.matches && result.matches.length) {
            for (var i = 0; i < result.matches.length; i++) {
              if ('title' === result.matches[i].key) {
                titleDiv.innerHTML = generateHighlightedText(result.matches[i].value, result.matches[i].indices);
              }

              if ('description' === result.matches[i].key) {
                descDiv = document.createElement('div');
                descDiv.setAttribute('class', 'menu-item__desc');
                descDiv.innerHTML = generateHighlightedText(result.item.description, result.matches[i].indices);
              } else if ('content' === result.matches[i].key) {
                if (!descDiv) {
                  descDiv = document.createElement('div');
                  descDiv.setAttribute('class', 'menu-item__desc');
                  descDiv.innerHTML = generateHighlightedText(result.item.content.substring(0, 150), result.matches[i].indices);
                }
              } else {
                if (result.item.description) {
                  descDiv = document.createElement('div');
                  descDiv.setAttribute('class', 'menu-item__desc');
                  descDiv.innerHTML = result.item.description;
                } else {
                  descDiv = document.createElement('div');
                  descDiv.setAttribute('class', 'menu-item__desc');
                  descDiv.innerHTML = result.item.content.substring(0, 150);
                }
              }
            }
            
            li.appendChild(titleDiv);
            if (descDiv) {
              li.appendChild(descDiv);
            }
            ul.appendChild(a);
          }
        });
      } else {
        var li = document.createElement('li');
        li.setAttribute('class', 'dropdown-item');
        li.innerText = 'No results found';
        ul.appendChild(li);
      }

      while (searchMenu.hasChildNodes()) {
        searchMenu.removeChild(
          searchMenu.lastChild
        );
      }
      searchMenu.appendChild(ul);
    }

    function renderSearchResultsMobile(searchText, results) {
      searchResults = document.getElementById('search-mobile-results');

      var content = document.createElement('div');
      content.setAttribute('class', 'mobile-search__content');

      if (results.length > 0) {
        results.forEach(function (result) {
          var item = document.createElement('a');
          item.setAttribute('href', result.uri);
          item.innerHTML = '<div class="mobile-search__item"><div class="mobile-search__item--title">📄 ' + result.title + '</div><div class="mobile-search__item--desc">' + (result.description ? result.description : result.content) + '</div></div>';
          content.appendChild(item);
        });
      } else {
        var item = document.createElement('span');
        content.appendChild(item);
      }

      let wrap = document.getElementById('search-mobile-results');
      while (wrap.firstChild) {
        wrap.removeChild(wrap.firstChild)
      }
      searchResults.appendChild(content);      
    }

    function renderSearchHighlightResultsMobile(searchText, results) {
      searchResults = document.getElementById('search-mobile-results');

      var ul = document.createElement('div');
      ul.setAttribute('class', 'mobile-search__content');

      if (results.length) {
        results.forEach(function (result) {
          var li = document.createElement('li');
          var a = document.createElement('a');
          var descDiv = null;

          a.setAttribute('href', result.item.uri);
          a.appendChild(li);
          li.setAttribute('class', 'mobile-search__item');

          var titleDiv = document.createElement('div');
          titleDiv.innerHTML = result.item.title;
          titleDiv.setAttribute('class', 'mobile-search__item--title');
          
          if (result.matches && result.matches.length) {
            for (var i = 0; i < result.matches.length; i++) {
              if ('title' === result.matches[i].key) {
                titleDiv.innerHTML = generateHighlightedText(result.matches[i].value, result.matches[i].indices);
              }

              if ('description' === result.matches[i].key) {
                descDiv = document.createElement('div');
                descDiv.setAttribute('class', 'mobile-search__item--desc');
                descDiv.innerHTML = generateHighlightedText(result.item.description, result.matches[i].indices);
              } else if ('content' === result.matches[i].key) {
                if (!descDiv) {
                  descDiv = document.createElement('div');
                  descDiv.setAttribute('class', 'mobile-search__item--desc');
                  descDiv.innerHTML = generateHighlightedText(result.item.content.substring(0, 150), result.matches[i].indices);
                }
              } else {
                if (result.item.description) {
                  descDiv = document.createElement('div');
                  descDiv.setAttribute('class', 'mobile-search__item--desc');
                  descDiv.innerHTML = result.item.description;
                } else {
                  descDiv = document.createElement('div');
                  descDiv.setAttribute('class', 'mobile-search__item--desc');
                  descDiv.innerHTML = result.item.content.substring(0, 150);
                }
              }
            }
            
            li.appendChild(titleDiv);
            if (descDiv) {
              li.appendChild(descDiv);
            }
            ul.appendChild(a);
          }
        });
      } else {
        var item = document.createElement('span');
        ul.appendChild(item);
      }

      let wrap = document.getElementById('search-mobile-results');
      while (wrap.firstChild) {
        wrap.removeChild(wrap.firstChild)
      }
      searchResults.appendChild(ul);
    }

    function generateHighlightedText(text, regions) {
      if (!regions) {
        return text;
      }

      var content = '', nextUnhighlightedRegionStartingIndex = 0;

      regions.forEach(function(region) {
        if (region[0] === region[1]) {
          return null;
        }
        
        content += '' +
          text.substring(nextUnhighlightedRegionStartingIndex, region[0]) +
          '<span class="search__highlight">' +
            text.substring(region[0], region[1] + 1) +
          '</span>' +
        '';
        nextUnhighlightedRegionStartingIndex = region[1] + 1;
      });

      content += text.substring(nextUnhighlightedRegionStartingIndex);

      return content;
    };

    var searchElem = document.getElementById('search');
    var searchMobile = document.getElementById('search-mobile');
    var searchResultsContainer = document.getElementById('search-results');

    searchElem ?
    searchElem.addEventListener('input', function(e) {
      if (!e.target.value | window.innerWidth < 770) {
        searchResultsContainer ? searchResultsContainer.setAttribute('class', 'dropdown') : null;
        searchResult ? searchResult.setAttribute('data-display', 'none') : null;
        summaryContainer ? summaryContainer.setAttribute('data-display', 'block') : null;
        return null;
      }

      searchText = e.target.value;
      var results = fuse.search(e.target.value);
      
      if (searchResultPosition === "main") {
        if (enableSearchHighlight) {
          renderSearchHighlightResultsMain(searchText, results);
        } else {
          renderSearchResultsMain(searchText, results);
        }
      } else {
        if (enableSearchHighlight) {
          renderSearchHighlightResultsSide(searchText, results);
        } else {
          renderSearchResultsSide(searchText, results);
        }
        
        var dropdownItems = searchResultsContainer.querySelectorAll('.dropdown-item');
        dropdownItems ? dropdownItems.forEach(function(item) {
          item.addEventListener('mousedown', function(e) {
            e.target.click();
          });
        }) : null;
      }
    }) : null;

    searchElem ? 
    searchElem.addEventListener('blur', function() {
      if (window.innerWidth < 770) {
        return null;
      }
      searchResultsContainer ? searchResultsContainer.setAttribute('class', 'dropdown') : null;
    }) : null;

    searchElem ? 
    searchElem.addEventListener('click', function(e) {
      if (window.innerWidth < 770) {
        return null;
      }
      if (!e.target.value) {
        searchResultsContainer ? searchResultsContainer.setAttribute('class', 'dropdown') : null;
        return null;
      }

      searchText = e.target.value;
      var results = fuse.search(e.target.value);

      if (searchResultPosition === "main") {
        if (enableSearchHighlight) {
          renderSearchHighlightResultsMain(searchText, results);
        } else {
          renderSearchResultsMain(searchText, results);
        }
      } else{
        if (enableSearchHighlight) {
          renderSearchHighlightResultsSide(searchText, results);
        } else {
          renderSearchResultsSide(searchText, results);
        }

        var dropdownItems = searchResultsContainer.querySelectorAll('.dropdown-item');
        dropdownItems ? dropdownItems.forEach(function (item) {
          item.addEventListener('mousedown', function (e) {
            e.target.click();
          });
        }) : null;
      }
    }) : null;

    var searchMenuElem = document.getElementById("search-menu");
    var activeItem = document.querySelector('#search-menu .dropdown-item.is-active');
    var activeIndex = null;
    var items = null;
    var searchContainerMaxHeight = 350;

    searchElem ? 
    searchElem.addEventListener('keydown', function(e) {
      if (window.innerWidth < 770) {
        return null;
      }

      if (e.key === 'Escape') {
        searchResult ? searchResult.setAttribute('data-display', 'none') : null;
        summaryContainer ? summaryContainer.setAttribute('data-display', 'block') : null;
      }

      var items = document.querySelectorAll('#search-menu .dropdown-item');
      var keyCode = e.which || e.keyCode;

      if (!items || !items.length) {
        return null;
      }
      
      if (e.key === 'ArrowDown' || keyCode === 40) {
        if (activeIndex === null) {
          activeIndex = 0;
          items[activeIndex].classList.remove('is-active');
        } else {
          items[activeIndex].classList.remove('is-active');
          activeIndex = activeIndex === items.length - 1 ? 0 : activeIndex + 1;
        }
        items[activeIndex].classList.add('is-active');

        let overflowedPixel = items[activeIndex].offsetTop + items[activeIndex].clientHeight - searchContainerMaxHeight;
        if (overflowedPixel > 0) {
          document.querySelector(".search-content").scrollTop += items[activeIndex].getBoundingClientRect().height;
        } else if (activeIndex === 0) {
          document.querySelector(".search-content").scrollTop = 0;
        }
      } else if (e.key === 'ArrowUp' || keyCode === 38) {
        if (activeIndex === null) {
          activeIndex = items.length - 1;
          items[activeIndex].classList.remove('is-active');
        } else {
          items[activeIndex].classList.remove('is-active');
          activeIndex = activeIndex === 0 ? items.length - 1 : activeIndex - 1;
        }
        items[activeIndex].classList.add('is-active');
        
        let overflowedPixel = items[activeIndex].offsetTop + items[activeIndex].clientHeight - searchContainerMaxHeight;
        if (overflowedPixel < 0) {
          document.querySelector(".search-content").scrollTop -= items[activeIndex].getBoundingClientRect().height;
        } else {
          document.querySelector(".search-content").scrollTop = overflowedPixel + items[activeIndex].getBoundingClientRect().height;
        }
      } else if (e.key === 'Enter' || keyCode === 13) {
        if (items[activeIndex] && items[activeIndex].getAttribute('href')) {
          location.href = items[activeIndex].getAttribute('href');
        }
      } else if (e.key === 'Escape' || keyCode === 27) {
        e.target.value = null;
        if (searchResults) {
          searchResults.classList.remove('is-active');
        }
      }
    }) : null;

    searchMobile ? 
    searchMobile.addEventListener('input', function(e) {
      if (!e.target.value) {
        let wrap = document.getElementById('search-mobile-results');
        while (wrap.firstChild) {
          wrap.removeChild(wrap.firstChild);
        }
        return null;
      }

      searchText = e.target.value;
      var results = fuse.search(e.target.value);
      renderSearchResultsMobile(searchText, results);
      if (enableSearchHighlight) {
        renderSearchHighlightResultsMobile(searchText, results);
      } else {
        renderSearchResultsMobile(searchText, results);
      }
    }) : null;
  


  
    var mobileSearchInputElem = document.querySelector('#search-mobile');
    var mobileSearchClassElem = document.querySelector('.mobile-search');
    var mobileSearchBtnElems = document.querySelectorAll('.navbar-search');
    var mobileSearchCloseBtnElem = document.querySelector('#search-mobile-close');
    var mobileSearchContainer = document.querySelector('#search-mobile-container');
    var mobileSearchResultsElem = document.querySelector('#search-mobile-results');
    var htmlElem = document.querySelector('html');

    if (mobileSearchClassElem) {
      mobileSearchClassElem.style.display = 'none';
    }

    mobileSearchBtnElems ? 
    mobileSearchBtnElems.forEach(function (elem, idx) {
      elem.addEventListener('click', function () {
        if (mobileSearchContainer) {
          mobileSearchContainer.style.display = 'block';
        }

        if (mobileSearchInputElem) {
          mobileSearchInputElem.focus();
        }

        if (htmlElem) {
          htmlElem.style.overflowY = 'hidden';
        }
      });
    }) : null;

    mobileSearchCloseBtnElem ? 
    mobileSearchCloseBtnElem.addEventListener('click', function() {
      if (mobileSearchContainer) {
        mobileSearchContainer.style.display = 'none';
      }

      if (mobileSearchInputElem) {
        mobileSearchInputElem.value = '';
      }
      
      if (mobileSearchResultsElem) {
        while (mobileSearchResultsElem.firstChild) {
          mobileSearchResultsElem.removeChild(mobileSearchResultsElem.firstChild);
        }
      }

      if (htmlElem) {
        htmlElem.style.overflowY = 'visible';
      }
    }) : null;

    mobileSearchInputElem ?
    mobileSearchInputElem.addEventListener('keydown', function(e) {
      var keyCode = e.which || e.keyCode;
      if (e.key === 'Escape' || keyCode === 27) {
        if (mobileSearchContainer) {
          mobileSearchContainer.style.display = 'none';
        }
        
        if (mobileSearchInputElem) {
          mobileSearchInputElem.value = '';
        }

        if (mobileSearchResultsElem) {
          while (mobileSearchResultsElem.firstChild) {
            mobileSearchResultsElem.removeChild(mobileSearchResultsElem.firstChild);
          }
        }
        if (htmlElem) {
          htmlElem.style.overflowY = 'visible';
        }
      }
    }) : null;
  


  
    function renderSearchResultsMain(searchText, results) {
      var searchBody = document.querySelector('.search-result__body');
      var originUl = searchBody.querySelector('ul');
      var ul = document.createElement('ul');
      
      if (!searchText) {
        searchResult ? searchResult.setAttribute('data-display', 'none') : null;
        summaryContainer ? summaryContainer.setAttribute('data-display', 'block') : null;
      } else if (results) {
        if (results && results.length) {
          results.forEach(function (result) {
            makeLi(ul, result);
          });

          searchResult ? searchResult.setAttribute('data-display', 'block') : null;
          summaryContainer ? summaryContainer.setAttribute('data-display', 'none') : null;
        }
      }

      originUl.parentNode.replaceChild(ul, originUl);
    }

    function renderSearchHighlightResultsMain(searchText, results) {
      var searchBody = document.querySelector('.search-result__body');
      var originUl = searchBody.querySelector('ul');
      var ul = document.createElement('ul');

      if (!searchText) {
        searchResult ? searchResult.setAttribute('data-display', 'none') : null;
        summaryContainer ? summaryContainer.setAttribute('data-display', 'block') : null;
      } else if (results) {
        if (results && results.length) {
          results.forEach(function (result) {
            makeHighlightLi(ul, result);
          });

          searchResult ? searchResult.setAttribute('data-display', 'block') : null;
          summaryContainer ? summaryContainer.setAttribute('data-display', 'none') : null;
        }
      }

      originUl.parentNode.replaceChild(ul, originUl);
    }
  
  });
</script>    
    


<link rel="stylesheet" href="/css/main.min.css">


    
<meta name="description" content="Dart 语言基础和一些特点(相比 Java)" />


<meta name="created" content="2019-03-01T15:09:34&#43;0000">
<meta name="modified" content="2019-03-01T15:09:34&#43;0000">
<meta property="article:published_time" content="2019-03-01T15:09:34&#43;0000">

<meta name="author" content="Yang">


<meta property="og:site_name" content="Yang Blog">
<meta property="og:title" content="Dartlang">
<meta property="og:url" content="https://jiyang.site/posts/2019-03-01-dartlang/">
<meta property="og:type" content="article">
<meta property="og:description" content="Dart 语言基础和一些特点(相比 Java)">

<meta name="generator" content="Hugo 0.81.0" />
<meta name="msapplication-TileColor" content="#fff">

<meta name="theme-color" content="#fff">

<meta name="msapplication-navbutton-color" content="#fff">

<meta name="apple-mobile-web-app-status-bar-style" content="#fff">

<link rel="canonical" href="https://jiyang.site/posts/2019-03-01-dartlang/">

<link rel="manifest" href="/manifest.json">

  
  <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
  <link rel="icon" href="/favicon.png" sizes="any" type="image/png" />
  


    <script type="application/ld+json">
  {
    "@context": "https://schema.org",
    "@type": "WebPage",
    "headline": "Dartlang",
    "datePublished": "2019-03-01T15:09:34Z",
    "dateModified": "2019-03-01T15:09:34Z",
    "url" : "https://jiyang.site/posts/2019-03-01-dartlang/",
    "description": "Dart 语言基础和一些特点(相比 Java)",
    "mainEntityOfPage": {
      "@type": "WebPage",
      "@id": "https://jiyang.site/"
    },
    "publisher": {
      "@type": "Organization",
      "name": "Yang Blog",
      "url": "https://jiyang.site/"
    }
  }
</script>

    
  
<script type="application/javascript">
var doNotTrack = false;
if (!doNotTrack) {
	(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
	(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
	m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
	})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
	ga('create', 'UA-114920988-1', 'auto');
	
	ga('send', 'pageview');
}
</script>

  
<script type="application/javascript">
var doNotTrack = false;
if (!doNotTrack) {
	window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
	ga('create', 'UA-114920988-1', 'auto');
	
	ga('send', 'pageview');
}
</script>
<script async src='https://www.google-analytics.com/analytics.js'></script>







  <script>
    
    var baiduAnalyticsId = JSON.parse("\"3fa649da4559b0b0f5ac81098a21ef91\"");

    var _hmt = _hmt || [];
    (function () {
      var hm = document.createElement("script");
      hm.src = "https://hm.baidu.com/hm.js?" + baiduAnalyticsId;
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(hm, s);
    })();
  </script>


    
</head>

<body id="root" class="theme__light">
    <script>
        var localTheme = localStorage.getItem('theme');
        if (localTheme) {
            document.getElementById('root').className = 'theme__' + localTheme;
        }
    </script>
    <div id="container">
        





        <div class="wrapper" data-type="posts" data-kind="page">
            <nav class="navbar scrolling" role="navigation" aria-label="main navigation" data-dir="ltr">
  <div class="navbar__brand">
    
    &nbsp;&nbsp;
    
    
      <a href="/" title="Home" rel="home" class="navbar__title-link">
        <h6 class="navbar__title">YangBlog</h6>
      </a>
    
  </div>

  
<div class="theme theme-mobile" data-ani="true">
  <div class="dropdown">
    <button class="dropdown-trigger navbar__slide-down" aria-label="Select Theme Button" style="" data-ani="true">
      <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24"><path fill="none" d="M24 0H0v24h24V0z"/><path fill="currentColor" d="M6.34 7.93c-3.12 3.12-3.12 8.19 0 11.31C7.9 20.8 9.95 21.58 12 21.58s4.1-.78 5.66-2.34c3.12-3.12 3.12-8.19 0-11.31l-4.95-4.95c-.39-.39-1.02-.39-1.41 0L6.34 7.93zM12 19.59c-1.6 0-3.11-.62-4.24-1.76C6.62 16.69 6 15.19 6 13.59s.62-3.11 1.76-4.24L12 5.1v14.49z"/></svg>      
    </button>
    <div class="dropdown-content select-theme">
      
        
        <a href="#" class="dropdown-item select-theme__item is-active">
          light
        </a>
        
        <a href="#" class="dropdown-item select-theme__item ">
          dark
        </a>
        
        <a href="#" class="dropdown-item select-theme__item ">
          hacker
        </a>
        
        <a href="#" class="dropdown-item select-theme__item ">
          solarized
        </a>
        
        <a href="#" class="dropdown-item select-theme__item ">
          kimbie
        </a>
        
      
    </div>
  </div>
</div>


<div class="mobile-search__btn navbar-search" data-ani="true">
  <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" fill="currentColor" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M15.5 14h-.79l-.28-.27c1.2-1.4 1.82-3.31 1.48-5.34-.47-2.78-2.79-5-5.59-5.34-4.23-.52-7.79 3.04-7.27 7.27.34 2.8 2.56 5.12 5.34 5.59 2.03.34 3.94-.28 5.34-1.48l.27.28v.79l4.25 4.25c.41.41 1.08.41 1.49 0 .41-.41.41-1.08 0-1.49L15.5 14zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/></svg>
</div>

<div id="search-mobile-container" class="mobile-search hide" data-dir="ltr">
  <div class="mobile-search__top">
    <input id="search-mobile" type="text" aria-label="Mobile Search" placeholder="Search" class="mobile-search__top--input"/>
    <div id="search-mobile-close" class="mobile-search__top--icon">
      <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24"><path opacity=".87" fill="none" d="M0 0h24v24H0V0z"/><path fill="currentColor" d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm3.59-13L12 10.59 8.41 7 7 8.41 10.59 12 7 15.59 8.41 17 12 13.41 15.59 17 17 15.59 13.41 12 17 8.41z"/></svg>
    </div>
  </div>
  <div id="search-mobile-results" class="mobile-search__body">
    
  </div>
</div>


<a role="button" class="navbar__burger" aria-label="menu" aria-expanded="false"
  data-ani="true">
  <span aria-hidden="true"></span>
  <span aria-hidden="true"></span>
  <span aria-hidden="true"></span>
</a>
<div class="navbarm__collapse" data-open="false">
  <ul dir="ltr">
    
    
      
      
      
      

      
        <li class="navbarm__menu--item ">
          <a href="/categories">category</a>
        </li>
      
      
    
      
      
      
      

      
        <li class="navbarm__menu--item active">
          <a href="/posts">posts</a>
        </li>
      
      
    

    
      <li class="navbarm__menu--item ">
        <a href="/tags" class="navbarm__menu--term" data-index="0">
          Tags
        </a>
      </li>
    
      <li class="navbarm__menu--item ">
        <a href="/categories" class="navbarm__menu--term" data-index="1">
          Categories
        </a>
      </li>
    
      <li class="navbarm__menu--item ">
        <a href="/series" class="navbarm__menu--term" data-index="2">
          Series
        </a>
      </li>
    
  </ul>
</div>
  <div class="navbar__menu">
  
  
  
<div class="theme" data-ani="true">
  <div class="dropdown">
    <button class="dropdown-trigger navbar__slide-down" aria-label="Select Theme Button" data-ani="true">
      <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24"><path fill="none" d="M24 0H0v24h24V0z"/><path fill="currentColor" d="M6.34 7.93c-3.12 3.12-3.12 8.19 0 11.31C7.9 20.8 9.95 21.58 12 21.58s4.1-.78 5.66-2.34c3.12-3.12 3.12-8.19 0-11.31l-4.95-4.95c-.39-.39-1.02-.39-1.41 0L6.34 7.93zM12 19.59c-1.6 0-3.11-.62-4.24-1.76C6.62 16.69 6 15.19 6 13.59s.62-3.11 1.76-4.24L12 5.1v14.49z"/></svg>      
    </button>
    <div class="dropdown-content select-theme">
      
        
        <a href="#" class="dropdown-item select-theme__item is-active">
          light
        </a>
        
        <a href="#" class="dropdown-item select-theme__item ">
          dark
        </a>
        
        <a href="#" class="dropdown-item select-theme__item ">
          hacker
        </a>
        
        <a href="#" class="dropdown-item select-theme__item ">
          solarized
        </a>
        
        <a href="#" class="dropdown-item select-theme__item ">
          kimbie
        </a>
        
      
    </div>
  </div>
</div>

  
  
  
  
  
  
  
  <a href="/categories" class="navbar__menu-item navbar__slide-down " dir="ltr" data-ani="true">category</a>
  
  
  
  
  
  
  
  <a href="/posts" class="navbar__menu-item navbar__slide-down active" dir="ltr" data-ani="true">posts</a>
  
  
</div>
</nav>
            
            

<main class="single__main main-main">
  
    <nav class="breadcrumb hide" aria-label="breadcrumbs">
  <script>document.querySelector('.breadcrumb').classList.remove('hide')</script>
  <ol>
    
  
  
  
  
  
  <li >
    
      <a href="https://jiyang.site/" class="capitalize">Yang Blog</a>
    
  </li>
  
  
  <li >
    
      <a href="https://jiyang.site/posts/" class="capitalize">Posts</a>
    
  </li>
  
  
  <li  class="is-active" >
    
      <span>Dartlang</span>
    
  </li>
  
  </ol>
  
</nav>
  
  
  <div class="single ">
    <div class="single__nojs">This page looks best with JavaScript enabled</div>
    <script>document.querySelector('.single').classList.remove('hide'); document.querySelector('.single__nojs').classList.add('hide');</script>
    <h2 class="single__title" data-ani="true">Dartlang</h2>
    <h3 class="single__subtitle"></h3>
    <div class="single__meta">
      
<div class="single__infos">
  <time class="single__info" title="Written At">📅&nbsp;Mar 1, 2019 </time>
  
  &nbsp;&middot;&nbsp; <span class="single__info" title="Reading Time"> ☕&nbsp;10&nbsp;min read </span>
  
  <span class="single__info">
    
  </span>
</div>

      
<ul class="single__tags caption">
  

</ul>

    </div>
    <article class="single__contents" data-dir="ltr" data-ani="true">
      
      <h2 id="特别点">特别点</h2>
<ul>
<li>任何能作为变量使用的都是对象, 每一个对象都是一个类的实例. 甚至 数组, 函数, null 都是对象,所有对象都继承自 <code>Object</code> class.</li>
<li>Dart 是强类型的语言,但是也支持类型推导, 比如 <code>final a = 1</code> 会推导出 <code>a</code> 是 <code>int</code>.  还可以使用 <code>dynamic</code>表示类型在运行时才确定</li>
<li>Dart 支持泛型,例如 <code>List&lt;int&gt;</code>(一个 int 集合), <code>List&lt;dynamic&gt;</code>(任何类型的对象的集合).</li>
<li>Dart 支持 <code>top-level</code>函数,  类实例函数, 类静态函数, 嵌套函数, 局部函数.</li>
<li>Dart 支持 <code>top-level</code>变量, 类实例变量, 类静态变量.</li>
<li>Dart 只有 library 私有 和 library 公有 两种可见性, 以 <code>_</code> 开头的标识符就代表 library 私有. 比如<code>int _privateNum = 0;</code></li>
<li>Dart 支持条件表达式, <code>condition ? expr1 : expr2</code>.</li>
</ul>
<h2 id="特别的关键字">特别的关键字</h2>
<blockquote>
<p>以下是和 Java 比较起来, Dart 中一些特别用途的关键字.</p>
</blockquote>
<ul>
<li>
<p>dynamic</p>
<ul>
<li>声明一个类型是任意类型的, 表示变量类型在运行时才确定</li>
</ul>
</li>
</ul>
<h3 id="library-相关">library 相关</h3>
<ul>
<li>
<p>show</p>
<ul>
<li>
<p>当只导入一个 library 的一部分时使用</p>
</li>
<li>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="c1">// Import only foo.
</span><span class="c1"></span><span class="k">import</span> <span class="s1">&#39;package:lib1/lib1.dart&#39;</span> <span class="k">show</span> <span class="n">foo</span><span class="p">;</span>
</code></pre></td></tr></table>
</div>
</div></li>
</ul>
</li>
<li>
<p>hide</p>
<ul>
<li>
<p>当导入一个 library 中所有内容, 但排除某个时使用</p>
</li>
<li>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="c1">// Import all names EXCEPT foo.
</span><span class="c1"></span><span class="k">import</span> <span class="s1">&#39;package:lib2/lib2.dart&#39;</span> <span class="k">hide</span> <span class="n">foo</span><span class="p">;</span>
</code></pre></td></tr></table>
</div>
</div></li>
</ul>
</li>
<li>
<p>as</p>
<ul>
<li>
<p>给导入的 library 指定别名</p>
</li>
<li>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="k">import</span> <span class="s1">&#39;package:lib2/lib2.dart&#39;</span> <span class="k">as</span> <span class="n">lib2</span><span class="p">;</span>
    
<span class="c1">// Uses Element from lib2.
</span><span class="c1"></span><span class="n">lib2</span><span class="p">.</span><span class="n">Element</span> <span class="n">element2</span> <span class="o">=</span> <span class="n">lib2</span><span class="p">.</span><span class="n">Element</span><span class="p">();</span>
</code></pre></td></tr></table>
</div>
</div></li>
</ul>
</li>
<li>
<p>deferred</p>
<ul>
<li>
<p>延期导入 library. 当需要使用时再导入, 使用场景:</p>
<ul>
<li>减少应用的启动时间</li>
<li>A/B Test</li>
<li>加载很少会用的的方法</li>
</ul>
</li>
</ul>
</li>
<li>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="c1">// 必须使用 deferred as
</span><span class="c1"></span><span class="k">import</span> <span class="s1">&#39;package:greetings/hello.dart&#39;</span> <span class="n">deferred</span> <span class="k">as</span> <span class="n">hello</span><span class="p">;</span>
  
<span class="c1">// 执行 loadLibrary 真正导入
</span><span class="c1"></span><span class="n">Future</span> <span class="n">greet</span><span class="p">()</span> <span class="kd">async</span> <span class="p">{</span>
  <span class="kd">await</span> <span class="n">hello</span><span class="p">.</span><span class="n">loadLibrary</span><span class="p">();</span>
  <span class="n">hello</span><span class="p">.</span><span class="n">printGreeting</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div></li>
<li>
<p><code>loadLibrary</code> 即使多次调用, library 也只会导入一次</p>
</li>
<li>
<p><strong>注意</strong></p>
<ul>
<li>延期导入的 library 中的常量, 直到 library 被真正导入后才可用</li>
<li>不能使用延期导入的 library 中的类型, 比如 <code>class</code> 等. 最好将包含类型声明的 library 移到一个 libraryA , 然后让 延期导入的 library 和导包的文件都导入这个 libraryA.</li>
<li><code>loadLibrary</code> 函数返回的是一个 <code>Future</code>, 需要注意异步使用.</li>
</ul>
</li>
<li>
<p>export</p>
<ul>
<li>在一个 dart 文件中批量 <code>export</code> 多个 library, 这样就只用 import 这一个文件</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="c1">// 在 shelf.dart 中声明如下:
</span><span class="c1"></span><span class="k">export</span> <span class="s1">&#39;src/cascade.dart&#39;</span><span class="p">;</span>
<span class="k">export</span> <span class="s1">&#39;src/handler.dart&#39;</span><span class="p">;</span>
<span class="k">export</span> <span class="s1">&#39;src/handlers/logger.dart&#39;</span><span class="p">;</span>
<span class="k">export</span> <span class="s1">&#39;src/hijack_exception.dart&#39;</span><span class="p">;</span>
<span class="k">export</span> <span class="s1">&#39;src/middleware.dart&#39;</span><span class="p">;</span>
<span class="k">export</span> <span class="s1">&#39;src/pipeline.dart&#39;</span><span class="p">;</span>
<span class="k">export</span> <span class="s1">&#39;src/request.dart&#39;</span><span class="p">;</span>
<span class="k">export</span> <span class="s1">&#39;src/response.dart&#39;</span><span class="p">;</span>
<span class="k">export</span> <span class="s1">&#39;src/server.dart&#39;</span><span class="p">;</span>
<span class="k">export</span> <span class="s1">&#39;src/server_handler.dart&#39;</span><span class="p">;</span>

<span class="c1">// 最后只用 import shelf.dart 一个包, 就能导入上面所有包
</span></code></pre></td></tr></table>
</div>
</div></li>
<li>
<p>part (不推荐使用)</p>
<ul>
<li>拆分一个 library 到多个文件</li>
</ul>
</li>
</ul>
<h3 id="异步编程支持">异步编程支持</h3>
<ul>
<li>
<p>async</p>
<ul>
<li>结合 <code>await</code> 使用</li>
</ul>
</li>
<li>
<p>await</p>
<ul>
<li>在使用 <code>async</code> 标记了的方法中, 等待一个 <code>Future</code> 执行完毕</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="n">Future</span><span class="o">&lt;</span><span class="kt">String</span><span class="o">&gt;</span> <span class="n">lookUpVersion</span><span class="p">()</span> <span class="o">=&gt;</span> <span class="n">Future</span><span class="p">.</span><span class="n">delayed</span><span class="p">(</span><span class="n">Duration</span><span class="p">(</span><span class="nl">seconds:</span> <span class="m">2</span><span class="p">),</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="s2">&#34;1.0&#34;</span><span class="p">);</span>

<span class="kt">void</span> <span class="n">checkVersion</span><span class="p">()</span> <span class="kd">async</span> <span class="p">{</span>
    <span class="kd">var</span> <span class="n">version</span> <span class="o">=</span> <span class="kd">await</span> <span class="n">lookUpVersion</span><span class="p">();</span>
    <span class="n">print</span><span class="p">(</span><span class="n">version</span><span class="p">);</span>  <span class="c1">// 1.0
</span><span class="c1"></span><span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div></li>
</ul>
<h3 id="generators-中使用">Generators 中使用</h3>
<ul>
<li>sync</li>
<li>yield</li>
</ul>
<h3 id="函数相关">函数相关</h3>
<ul>
<li>external
<ul>
<li>声明一个函数的具体实现在其他地方, 目前仅用于 DartVM 在不同平台实现同一个函数.</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="c1">// 声明
</span><span class="c1"></span><span class="kd">class</span> <span class="nc">Foo</span> <span class="p">{</span>
    <span class="n">external</span> <span class="kt">int</span> <span class="n">bar</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">);</span>
<span class="p">}</span>

<span class="c1">// dart2js 中实现
</span><span class="c1"></span><span class="err">@</span><span class="n">patch</span> <span class="kd">class</span> <span class="nc">Foo</span> <span class="p">{</span>
    <span class="err">@</span><span class="n">patch</span> <span class="kt">int</span> <span class="n">bar</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="n">somethingMagical</span><span class="p">(</span><span class="n">x</span><span class="p">);</span> 
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div></li>
<li>typedef
<ul>
<li>定义一个函数类型. 当一个函数分配给一个变量时, typedef 能够保留函数的类型信息</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="kd">typedef</span> <span class="n">Compare</span> <span class="o">=</span> <span class="kt">int</span> <span class="n">Function</span><span class="p">(</span><span class="kt">Object</span> <span class="n">a</span><span class="p">,</span> <span class="kt">Object</span> <span class="n">b</span><span class="p">);</span>

<span class="kt">int</span> <span class="n">sort</span><span class="p">(</span><span class="kt">Object</span> <span class="n">a</span><span class="p">,</span> <span class="kt">Object</span> <span class="n">b</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="m">0</span><span class="p">;</span>

<span class="kd">class</span> <span class="nc">SortedCollection</span> <span class="p">{</span>
  <span class="n">Compare</span> <span class="n">compare</span><span class="p">;</span>
  <span class="n">SortedCollection</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="n">compare</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
  <span class="n">SortedCollection</span> <span class="n">coll</span> <span class="o">=</span> <span class="n">SortedCollection</span><span class="p">(</span><span class="n">sort</span><span class="p">);</span>
  <span class="k">assert</span><span class="p">(</span><span class="n">coll</span><span class="p">.</span><span class="n">compare</span> <span class="k">is</span> <span class="n">Function</span><span class="p">);</span> <span class="c1">// True
</span><span class="c1"></span>  <span class="k">assert</span><span class="p">(</span><span class="n">coll</span><span class="p">.</span><span class="n">compare</span> <span class="k">is</span> <span class="n">Compare</span><span class="p">);</span>  <span class="c1">// True
</span><span class="c1"></span><span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div></li>
<li>Function
<ul>
<li>声明一个变量是函数类型</li>
</ul>
</li>
</ul>
<h3 id="类相关">类相关</h3>
<ul>
<li>
<p>factory</p>
<ul>
<li>声明一个构造函数并不总是创建一个新的实例, 也可能返回一个缓存对象, 一个子类对象</li>
<li>factory 构造函数不能访问 <code>this</code></li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="kd">factory</span> <span class="n">Logger</span><span class="p">(</span><span class="kt">String</span> <span class="n">name</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">_cache</span><span class="p">.</span><span class="n">containsKey</span><span class="p">(</span><span class="n">name</span><span class="p">))</span> <span class="p">{</span>
      <span class="k">return</span> <span class="n">_cache</span><span class="p">[</span><span class="n">name</span><span class="p">];</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
      <span class="kd">final</span> <span class="n">logger</span> <span class="o">=</span> <span class="n">Logger</span><span class="p">.</span><span class="n">_internal</span><span class="p">(</span><span class="n">name</span><span class="p">);</span>
      <span class="n">_cache</span><span class="p">[</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">logger</span><span class="p">;</span>
      <span class="k">return</span> <span class="n">logger</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div></li>
<li>
<p>mixin</p>
<blockquote>
<p>减少继承造成的复杂结构和多重继承下的问题</p>
</blockquote>
<ul>
<li>在多个类中复用一个类的代码, 而不用继承类(类似: 继承人们的资产, 且不用是他们的孩子)</li>
<li>当 继承 或 mixin 的类中有相同的方法时, 优先使用最后 <code>with</code> 的类中的方法</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="kd">class</span> <span class="nc">Teacher</span> <span class="p">{</span>
  <span class="kt">void</span> <span class="n">teaching</span><span class="p">()</span> <span class="o">=&gt;</span> <span class="n">print</span><span class="p">(</span><span class="s2">&#34;Something&#34;</span><span class="p">);</span>
<span class="p">}</span>

<span class="n">mixin</span> <span class="n">MathTeacher</span> <span class="p">{</span>
  <span class="kt">void</span> <span class="n">teaching</span><span class="p">()</span> <span class="o">=&gt;</span> <span class="n">print</span><span class="p">(</span><span class="s2">&#34;Math&#34;</span><span class="p">);</span>
<span class="p">}</span>

<span class="n">mixin</span> <span class="n">EnglishTeacher</span> <span class="p">{</span>
  <span class="kt">void</span> <span class="n">teaching</span><span class="p">()</span> <span class="o">=&gt;</span> <span class="n">print</span><span class="p">(</span><span class="s2">&#34;English&#34;</span><span class="p">);</span>
<span class="p">}</span>

<span class="kd">class</span> <span class="nc">SeniorSchoolTeacher</span> <span class="kd">with</span> <span class="n">MathTeacher</span><span class="p">,</span> <span class="n">EnglishTeacher</span> <span class="p">{}</span>

<span class="kt">void</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
  <span class="n">SeniorSchoolTeacher</span> <span class="n">teacher</span> <span class="o">=</span> <span class="n">SeniorSchoolTeacher</span><span class="p">();</span>
  <span class="n">teacher</span><span class="p">.</span><span class="n">teaching</span><span class="p">();</span> <span class="c1">// English
</span><span class="c1"></span><span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div></li>
<li>
<p>with</p>
<ul>
<li>声明使用 <code>mixin</code> 的类</li>
</ul>
</li>
<li>
<p>convariant</p>
<ul>
<li>允许用子类覆盖重写参数的类型</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="kd">class</span> <span class="nc">Animal</span> <span class="p">{</span>
    <span class="kt">void</span> <span class="n">chase</span><span class="p">(</span><span class="n">Animal</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span> <span class="p">...</span> <span class="p">}</span>
<span class="p">}</span>

<span class="kd">class</span> <span class="nc">Mouse</span> <span class="kd">extends</span> <span class="n">Animal</span> <span class="p">{</span> <span class="p">...</span> <span class="p">}</span>

<span class="kd">class</span> <span class="nc">Cat</span> <span class="kd">extends</span> <span class="n">Animal</span> <span class="p">{</span>
    <span class="c1">// 正常情况下,是不允许覆盖参数类型的,会报 Invalid override. 使用 covariant 表明我们知道自己在做什么, 将忽略报错
</span><span class="c1"></span>    <span class="kt">void</span> <span class="n">chase</span><span class="p">(</span><span class="n">covariant</span> <span class="n">Mouse</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span> <span class="p">...</span> <span class="p">}</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div></li>
<li>
<p>get set</p>
<ul>
<li>为一个类添加额外的 getter setter 属性</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="kd">class</span> <span class="nc">Rectangle</span> <span class="p">{</span>
  <span class="kt">int</span> <span class="n">left</span><span class="p">,</span> <span class="n">top</span><span class="p">,</span> <span class="n">width</span><span class="p">,</span> <span class="n">height</span><span class="p">;</span>

  <span class="kt">int</span> <span class="kd">get</span> <span class="n">right</span> <span class="o">=&gt;</span> <span class="n">left</span> <span class="o">+</span> <span class="n">width</span><span class="p">;</span>
  <span class="kd">set</span> <span class="n">right</span><span class="p">(</span><span class="kt">int</span> <span class="n">value</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="n">left</span> <span class="o">=</span> <span class="n">value</span> <span class="o">-</span> <span class="n">width</span><span class="p">;</span>

  <span class="kt">int</span> <span class="kd">get</span> <span class="n">bottom</span> <span class="o">=&gt;</span> <span class="n">top</span> <span class="o">+</span> <span class="n">height</span><span class="p">;</span>
  <span class="kd">set</span> <span class="n">bottom</span><span class="p">(</span><span class="kt">int</span> <span class="n">value</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="n">top</span> <span class="o">=</span> <span class="n">value</span> <span class="o">-</span> <span class="n">height</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="n">main</span><span class="p">(){</span>
    <span class="kd">final</span> <span class="n">rect</span> <span class="o">=</span> <span class="n">Rectangle</span><span class="p">(</span><span class="m">3</span><span class="p">,</span> <span class="m">4</span><span class="p">,</span> <span class="m">20</span><span class="p">,</span> <span class="m">15</span><span class="p">);</span>
    <span class="k">assert</span><span class="p">(</span><span class="n">rect</span><span class="p">.</span><span class="n">left</span> <span class="o">==</span> <span class="m">3</span><span class="p">);</span>
    <span class="n">rect</span><span class="p">.</span><span class="n">right</span> <span class="o">=</span> <span class="m">0</span><span class="p">;</span>
    <span class="k">assert</span><span class="p">(</span><span class="n">rect</span><span class="p">.</span><span class="n">left</span> <span class="o">==</span> <span class="o">-</span><span class="m">20</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div></li>
</ul>
<h3 id="异常">异常</h3>
<ul>
<li>rethrow
<ul>
<li>catch 一个异常之后,再次抛出</li>
<li>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"> <span class="kt">void</span> <span class="n">misbehave</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">try</span> <span class="p">{</span>
      <span class="kt">dynamic</span> <span class="n">foo</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
      <span class="n">print</span><span class="p">(</span><span class="n">foo</span><span class="o">++</span><span class="p">);</span> <span class="c1">// Runtime error
</span><span class="c1"></span>    <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="n">e</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">print</span><span class="p">(</span><span class="s1">&#39;misbehave() partially handled </span><span class="si">${</span><span class="n">e</span><span class="p">.</span><span class="n">runtimeType</span><span class="si">}</span><span class="s1">.&#39;</span><span class="p">);</span>
      <span class="n">rethrow</span><span class="p">;</span> <span class="c1">// Allow callers to see the exception.
</span><span class="c1"></span>    <span class="p">}</span>
  <span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div></li>
</ul>
</li>
</ul>
<h3 id="其他">其他</h3>
<ul>
<li>operator
<ul>
<li>操作符重载. 可以重载常见的操作符.</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="kd">class</span> <span class="nc">Point</span> <span class="p">{</span>
  <span class="kt">int</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">;</span>

  <span class="n">Point</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="n">x</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="n">y</span><span class="p">);</span>

  <span class="n">Point</span> <span class="kd">operator</span> <span class="o">+</span><span class="p">(</span><span class="n">Point</span> <span class="n">p</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="n">Point</span><span class="p">(</span><span class="n">x</span> <span class="o">+</span> <span class="n">p</span><span class="p">.</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">+</span> <span class="n">p</span><span class="p">.</span><span class="n">y</span><span class="p">);</span>

  <span class="n">Point</span> <span class="kd">operator</span> <span class="o">-</span><span class="p">(</span><span class="n">Point</span> <span class="n">p</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="n">Point</span><span class="p">(</span><span class="n">x</span> <span class="o">-</span> <span class="n">p</span><span class="p">.</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">-</span> <span class="n">p</span><span class="p">.</span><span class="n">y</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kd">final</span> <span class="n">p1</span> <span class="o">=</span> <span class="n">Point</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">2</span><span class="p">);</span>
    <span class="kd">final</span> <span class="n">p2</span> <span class="o">=</span> <span class="n">Point</span><span class="p">(</span><span class="m">2</span><span class="p">,</span> <span class="m">1</span><span class="p">);</span>
    <span class="k">assert</span><span class="p">((</span><span class="n">p1</span> <span class="o">+</span> <span class="n">p2</span><span class="p">).</span><span class="n">x</span> <span class="o">==</span> <span class="m">3</span><span class="p">);</span>
    <span class="k">assert</span><span class="p">((</span><span class="n">p1</span> <span class="o">-</span> <span class="n">p2</span><span class="p">).</span><span class="n">x</span> <span class="o">==</span> <span class="o">-</span><span class="m">1</span><span class="p">);</span>
    <span class="k">assert</span><span class="p">((</span><span class="n">p2</span> <span class="o">-</span> <span class="n">p1</span><span class="p">).</span><span class="n">x</span> <span class="o">==</span> <span class="m">1</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div></li>
</ul>
<h2 id="变量">变量</h2>
<ul>
<li>Dart 中的变量也是存储的对象的引用, 当在函数中传递时,与 Java 类似是 <strong>值传递</strong>.</li>
<li>没有初始化的变量默认为 <code>null</code>, 没有初始化的数字类型也是 <code>null</code>.</li>
<li><code>final</code> 声明不可变的变量. 类中的 <code>final</code> 属性, 必须在构造函数的 body 执行前被赋值.</li>
<li><code>const</code> 声明编译期常量.</li>
<li><code>static</code> 声明类变量和类方法, <strong>Dart 中的类变量和类方法不能通过类的实例调用</strong></li>
</ul>
<h2 id="built-in-type">Built-in Type</h2>
<ul>
<li>
<p>numbers</p>
<ul>
<li><code>int</code> 不超过 64 位的整数, 在 DartVM 是 <code>-2^63 to 2^63 - 1</code>, 在编译为 JS 后是 <code>-2^53 to 2^53 - 1</code></li>
<li><code>double</code> 64 位的双精度浮点</li>
</ul>
</li>
<li>
<p>strings</p>
<ul>
<li>对应类 <code>String</code></li>
<li>和 Java 类似, 也是不可变的</li>
<li>UTF-16 编码</li>
<li>使用单引号或双引号创建, 使用三个单引号可以写到多行</li>
<li>使用 <code>$</code> 将变量嵌入字符串</li>
<li>使用 <code>r''</code> 创建原始字符串</li>
<li><code>==</code> 操作符, 比较两个字符串的内容是否相等</li>
<li>const 声明的字符串字面量是编译期常量</li>
</ul>
</li>
<li>
<p>booleans</p>
<ul>
<li>关键字 <code>bool</code></li>
</ul>
</li>
<li>
<p>lists (also known as arrays)</p>
<ul>
<li>对应类 <code>List</code>, 类似 Java 中的 <code>ArrayList</code></li>
<li>快速创建 <code>var l = [1, 2, 3, 4, 5];</code></li>
<li>常量list <code>var constantList = const [1, 2, 3];</code> 常量 list 不能再 <code>add</code> 或 修改内部元素</li>
</ul>
</li>
<li>
<p>sets</p>
<ul>
<li>对应类 <code>Set</code></li>
<li>快速创建 <code>var s = {&quot;dog&quot;, &quot;pic&quot;, &quot;fish&quot;};</code></li>
</ul>
</li>
<li>
<p>maps</p>
<ul>
<li>对应类 <code>Map</code></li>
<li>快速创建</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="kd">var</span> <span class="n">gifts</span> <span class="o">=</span> <span class="p">{</span>
  <span class="c1">// Key: Value
</span><span class="c1"></span>  <span class="s1">&#39;first&#39;</span><span class="o">:</span> <span class="s1">&#39;partridge&#39;</span><span class="p">,</span>
  <span class="s1">&#39;second&#39;</span><span class="o">:</span> <span class="s1">&#39;turtledoves&#39;</span><span class="p">,</span>
  <span class="s1">&#39;fifth&#39;</span><span class="o">:</span> <span class="s1">&#39;golden rings&#39;</span>
<span class="p">};</span>
</code></pre></td></tr></table>
</div>
</div></li>
<li>
<p>runes (for expressing Unicode characters in a string)</p>
<ul>
<li>对应类 <code>Runes</code></li>
<li>UTF-32 编码的字符串</li>
<li>超过4个数的 uniCode 需要包裹在 <code>{}</code> 里</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="n">main</span><span class="p">()</span> <span class="p">{</span>
  <span class="kd">var</span> <span class="n">clapping</span> <span class="o">=</span> <span class="s1">&#39;</span><span class="se">\u{1f44f}</span><span class="s1">&#39;</span><span class="p">;</span>
  <span class="n">print</span><span class="p">(</span><span class="n">clapping</span><span class="p">);</span> <span class="c1">// 👏
</span><span class="c1"></span>  <span class="n">print</span><span class="p">(</span><span class="n">clapping</span><span class="p">.</span><span class="n">codeUnits</span><span class="p">);</span> 
  <span class="n">print</span><span class="p">(</span><span class="n">clapping</span><span class="p">.</span><span class="n">runes</span><span class="p">.</span><span class="n">toList</span><span class="p">());</span>

  <span class="n">Runes</span> <span class="n">input</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Runes</span><span class="p">(</span><span class="s1">&#39;</span><span class="se">\u2665</span><span class="s1">  </span><span class="se">\u{1f605}</span><span class="s1">  </span><span class="se">\u{1f60e}</span><span class="s1">  </span><span class="se">\u{1f47b}</span><span class="s1">  </span><span class="se">\u{1f596}</span><span class="s1">  </span><span class="se">\u{1f44d}</span><span class="s1">&#39;</span><span class="p">);</span>
  <span class="n">print</span><span class="p">(</span><span class="k">new</span> <span class="kt">String</span><span class="p">.</span><span class="n">fromCharCodes</span><span class="p">(</span><span class="n">input</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div></li>
<li>
<p>symbols</p>
<blockquote>
<p>Dart中的 symbol 是不透明的动态字符串名称，用于反映库中的元数据。 简而言之，symbol 是一种存储人类可读字符串与优化供计算机使用的字符串之间关系的方法。Reflection 是一种在运行时获取类型元数据的机制，如类中的方法数，它具有的构造函数数或函数中的参数数。 您甚至可以调用在运行时加载的类型的方法。在 Dart 反射中，dart:mirrors 包中提供了特定的类。 此库适用于 Web 应用程序和命令行应用程序。</p>
</blockquote>
<ul>
<li>对应类 <code>Symbol</code></li>
<li>感觉主要用在 Dart 的反射上</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="c1">// foo.dart
</span><span class="c1"></span><span class="k">library</span> <span class="n">foo_lib</span><span class="p">;</span>

<span class="kd">class</span> <span class="nc">Foo</span> <span class="p">{</span>
  <span class="n">m1</span><span class="p">()</span> <span class="o">=&gt;</span> <span class="n">print</span><span class="p">(</span><span class="s2">&#34;Inside m1&#34;</span><span class="p">);</span>

  <span class="n">m2</span><span class="p">()</span> <span class="o">=&gt;</span> <span class="n">print</span><span class="p">(</span><span class="s2">&#34;Inside m3&#34;</span><span class="p">);</span>
<span class="p">}</span>

<span class="c1">// main.dart
</span><span class="c1"></span><span class="k">import</span> <span class="s1">&#39;dart:mirrors&#39;</span><span class="p">;</span>
<span class="k">import</span> <span class="s1">&#39;foo.dart&#39;</span><span class="p">;</span>

<span class="n">main</span><span class="p">()</span> <span class="p">{</span>
  <span class="kd">final</span> <span class="n">libName</span> <span class="o">=</span> <span class="n">Symbol</span><span class="p">(</span><span class="s2">&#34;foo_lib&#34;</span><span class="p">);</span>
  <span class="kd">final</span> <span class="n">className</span> <span class="o">=</span> <span class="n">Symbol</span><span class="p">(</span><span class="s2">&#34;Foo&#34;</span><span class="p">);</span>

  <span class="n">MirrorSystem</span> <span class="n">mirror</span> <span class="o">=</span> <span class="n">currentMirrorSystem</span><span class="p">();</span>
  <span class="n">LibraryMirror</span> <span class="n">libraryMirror</span> <span class="o">=</span> <span class="n">mirror</span><span class="p">.</span><span class="n">findLibrary</span><span class="p">(</span><span class="n">libName</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">libraryMirror</span><span class="p">.</span><span class="n">declarations</span><span class="p">.</span><span class="n">containsKey</span><span class="p">(</span><span class="n">className</span><span class="p">))</span> <span class="p">{</span>
    <span class="n">ClassMirror</span> <span class="n">classMirror</span> <span class="o">=</span> <span class="n">libraryMirror</span><span class="p">.</span><span class="n">declarations</span><span class="p">[</span><span class="n">className</span><span class="p">];</span>
    <span class="n">classMirror</span><span class="p">.</span><span class="n">instanceMembers</span>
        <span class="p">.</span><span class="n">forEach</span><span class="p">((</span><span class="n">symbol</span><span class="p">,</span> <span class="n">methodMirror</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="n">print</span><span class="p">(</span><span class="n">symbol</span><span class="p">));</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div></li>
</ul>
<h2 id="functions">Functions</h2>
<ul>
<li>在 Dart 里, 函数也是对象, 对应类为 <code>Function</code>.</li>
<li>简短写法 <code>bool isOdd(int number) =&gt; number%2 != 0;</code></li>
<li>在函数的参数声明里可简写为: <code>T f(T e)</code></li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="c1">// 模拟一个 map 方法
</span><span class="c1"></span><span class="n">List</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">map</span><span class="o">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="n">E</span><span class="o">&gt;</span><span class="p">(</span><span class="n">Iterable</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">list</span><span class="p">,</span> <span class="n">T</span> <span class="n">f</span><span class="p">(</span><span class="n">E</span> <span class="n">e</span><span class="p">))</span> <span class="p">{</span>
  <span class="kd">final</span> <span class="n">result</span> <span class="o">=</span> <span class="n">List</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">();</span>
  <span class="n">list</span><span class="p">.</span><span class="n">forEach</span><span class="p">((</span><span class="n">item</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span><span class="n">result</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="n">f</span><span class="p">(</span><span class="n">item</span><span class="p">))});</span>
  <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
<span class="p">}</span>

<span class="n">main</span><span class="p">()</span> <span class="p">{</span>
  <span class="kd">final</span> <span class="n">ints</span> <span class="o">=</span> <span class="kd">const</span> <span class="p">[</span><span class="m">1</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="m">3</span><span class="p">,</span> <span class="m">4</span><span class="p">];</span>
  <span class="kd">final</span> <span class="n">ints2</span> <span class="o">=</span> <span class="n">map</span><span class="p">(</span><span class="n">ints</span><span class="p">,</span> <span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="n">i</span> <span class="o">*</span> <span class="n">i</span><span class="p">);</span>
  <span class="n">print</span><span class="p">(</span><span class="n">ints2</span><span class="p">);</span> <span class="c1">// 1, 4, 9, 16
</span><span class="c1"></span><span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><h3 id="参数">参数</h3>
<ul>
<li>支持两种类型参数, 必传参数和可选参数, 第一个参数为必传,第二个可以为可选参数</li>
<li>可选命名参数</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="c1">// a 必传. b,c 可选
</span><span class="c1"></span><span class="kt">void</span> <span class="n">f</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="p">{</span><span class="kt">int</span> <span class="n">b</span><span class="p">,</span> <span class="kt">int</span> <span class="n">c</span><span class="p">})</span> <span class="p">{}</span>
<span class="n">f</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="nl">b:</span> <span class="m">2</span><span class="p">);</span>
<span class="n">f</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="nl">c:</span> <span class="m">3</span><span class="p">);</span>
<span class="n">f</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="nl">b:</span> <span class="m">2</span><span class="p">,</span> <span class="nl">c:</span> <span class="m">3</span><span class="p">);</span>

<span class="c1">// a,b 都可选
</span><span class="c1"></span><span class="kt">void</span> <span class="n">f</span><span class="p">({</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">})</span> <span class="p">{}</span>
<span class="n">f</span><span class="p">();</span>
<span class="n">f</span><span class="p">(</span><span class="nl">a:</span> <span class="m">1</span><span class="p">);</span>
<span class="n">f</span><span class="p">(</span><span class="nl">b:</span> <span class="m">2</span><span class="p">);</span>
<span class="n">f</span><span class="p">(</span><span class="nl">a:</span> <span class="m">1</span><span class="p">,</span> <span class="nl">b:</span> <span class="m">2</span><span class="p">);</span>

<span class="c1">// b 默认值为 100
</span><span class="c1"></span><span class="kt">void</span> <span class="n">f</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="p">{</span><span class="kt">int</span> <span class="n">b</span> <span class="o">=</span> <span class="m">100</span><span class="p">})</span>
<span class="n">f</span><span class="p">(</span><span class="m">1</span><span class="p">);</span>
<span class="n">f</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="nl">b:</span> <span class="m">2</span><span class="p">);</span>
</code></pre></td></tr></table>
</div>
</div><ul>
<li>可选位置参数</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="c1">// c 可选
</span><span class="c1"></span><span class="kt">void</span> <span class="n">f</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">,</span> <span class="p">[</span><span class="kt">int</span> <span class="n">c</span><span class="p">]){}</span>
<span class="n">f</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">2</span><span class="p">);</span>
<span class="n">f</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="m">3</span><span class="p">);</span>

<span class="c1">// c,d 为可选, d 默认值为 100
</span><span class="c1"></span><span class="kt">void</span> <span class="n">f</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">,</span> <span class="p">[</span><span class="kt">int</span> <span class="n">c</span><span class="p">,</span> <span class="kt">int</span> <span class="n">d</span> <span class="o">=</span> <span class="m">100</span><span class="p">]){}</span>
<span class="n">f</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">2</span><span class="p">);</span>
<span class="n">f</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="m">3</span><span class="p">);</span>
<span class="n">f</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="m">3</span><span class="p">,</span> <span class="m">4</span><span class="p">);</span>
</code></pre></td></tr></table>
</div>
</div><h3 id="main-函数">main 函数</h3>
<ul>
<li>程序的入口</li>
<li>参数 <code>List&lt;String&gt;</code> 可选</li>
</ul>
<h3 id="函数作为参数">函数作为参数</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="kt">void</span> <span class="n">printElement</span><span class="p">(</span><span class="kt">int</span> <span class="n">element</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">print</span><span class="p">(</span><span class="n">element</span><span class="p">);</span>
<span class="p">}</span>

<span class="kd">var</span> <span class="n">list</span> <span class="o">=</span> <span class="p">[</span><span class="m">1</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="m">3</span><span class="p">];</span>

<span class="c1">// printElement 作为参数.
</span><span class="c1"></span><span class="n">list</span><span class="p">.</span><span class="n">forEach</span><span class="p">(</span><span class="n">printElement</span><span class="p">);</span>
</code></pre></td></tr></table>
</div>
</div><p>变量存储函数引用</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="kd">var</span> <span class="n">loudify</span> <span class="o">=</span> <span class="p">(</span><span class="n">msg</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="s1">&#39;!!! </span><span class="si">${</span><span class="n">msg</span><span class="p">.</span><span class="n">toUpperCase</span><span class="p">()</span><span class="si">}</span><span class="s1"> !!!&#39;</span><span class="p">;</span>
<span class="k">assert</span><span class="p">(</span><span class="n">loudify</span><span class="p">(</span><span class="s1">&#39;hello&#39;</span><span class="p">)</span> <span class="o">==</span> <span class="s1">&#39;!!! HELLO !!!&#39;</span><span class="p">);</span>
</code></pre></td></tr></table>
</div>
</div><h3 id="匿名函数">匿名函数</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="p">([[</span><span class="n">Type</span><span class="p">]</span> <span class="n">param1</span><span class="p">[,</span> <span class="err">…</span><span class="p">]])</span> <span class="p">{</span> 
  <span class="n">codeBlock</span><span class="p">;</span> 
<span class="p">};</span>
</code></pre></td></tr></table>
</div>
</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="kd">var</span> <span class="n">list</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;apples&#39;</span><span class="p">,</span> <span class="s1">&#39;bananas&#39;</span><span class="p">,</span> <span class="s1">&#39;oranges&#39;</span><span class="p">];</span>
<span class="n">list</span><span class="p">.</span><span class="n">forEach</span><span class="p">((</span><span class="n">item</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">print</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">${</span><span class="n">list</span><span class="p">.</span><span class="n">indexOf</span><span class="p">(</span><span class="n">item</span><span class="p">)</span><span class="si">}</span><span class="s1">: </span><span class="si">$</span><span class="n">item</span><span class="s1">&#39;</span><span class="p">);</span>
<span class="p">});</span>
</code></pre></td></tr></table>
</div>
</div><p>如果函数只包含一行,可以使用剪头符号:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="n">list</span><span class="p">.</span><span class="n">forEach</span><span class="p">((</span><span class="n">item</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="n">print</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">${</span><span class="n">list</span><span class="p">.</span><span class="n">indexOf</span><span class="p">(</span><span class="n">item</span><span class="p">)</span><span class="si">}</span><span class="s1">: </span><span class="si">$</span><span class="n">item</span><span class="s1">&#39;</span><span class="p">));</span>
</code></pre></td></tr></table>
</div>
</div><h2 id="operators">Operators</h2>
<ul>
<li>
<p>乘除运算符</p>
<ul>
<li><code>~/</code> 取模: <code>201 ~/ 100 == 2</code></li>
<li><code>/</code>  商: double 结果 <code>1 / 100 == 0.01</code>, <code>100 / 1 == 100.0</code></li>
<li><code>%</code>  取余: <code>3 % 5 == 3</code></li>
</ul>
</li>
<li>
<p>类型测试符</p>
<ul>
<li><code>as</code> 类型转换</li>
<li><code>is</code> 如果对象拥有指明的类型, true</li>
<li><code>is!</code> 如果对象拥有指明的类型, false</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="m">1</span> <span class="k">is</span> <span class="kt">int</span> <span class="c1">//true
</span><span class="c1"></span><span class="m">1</span> <span class="k">is</span><span class="o">!</span> <span class="kt">int</span> <span class="c1">//false
</span><span class="c1"></span><span class="m">1</span> <span class="k">is</span><span class="o">!</span> <span class="kt">String</span> <span class="c1">//true
</span></code></pre></td></tr></table>
</div>
</div></li>
<li>
<p>赋值运算符</p>
<ul>
<li><code>??=</code> 如果被赋值的变量是 <code>null</code>, 则将右值赋给它; 否则不进行赋值</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="kt">int</span> <span class="n">d</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="n">d</span> <span class="o">??=</span> <span class="m">1</span><span class="p">;</span>
<span class="n">print</span><span class="p">(</span><span class="n">d</span><span class="p">);</span> <span class="c1">// 1
</span><span class="c1"></span><span class="n">d</span> <span class="o">??=</span> <span class="m">2</span><span class="p">;</span>
<span class="n">print</span><span class="p">(</span><span class="n">d</span><span class="p">);</span> <span class="c1">// 1
</span></code></pre></td></tr></table>
</div>
</div></li>
<li>
<p>条件表达式</p>
<ul>
<li>三目运算: <code>condition ? expr1 : expr2</code></li>
<li>条件赋值: <code>expr1 ?? expr2</code>, 如果 <code>expr1</code> 不为 <code>null</code>, 就返回 <code>expr1</code> 的值; 否则返回 <code>expr2</code> 的值</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="n">print</span><span class="p">(</span><span class="kc">null</span> <span class="o">??</span> <span class="m">100</span><span class="p">);</span>   <span class="c1">// 100
</span><span class="c1"></span><span class="n">print</span><span class="p">(</span><span class="kc">null</span> <span class="o">??</span> <span class="kc">null</span><span class="p">);</span>  <span class="c1">// null
</span><span class="c1"></span><span class="n">print</span><span class="p">(</span><span class="m">100</span> <span class="o">??</span> <span class="kc">null</span><span class="p">);</span>   <span class="c1">// 100
</span></code></pre></td></tr></table>
</div>
</div></li>
<li>
<p>null 安全访问符: <code>?.</code></p>
</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="kt">int</span> <span class="n">a</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="n">print</span><span class="p">(</span><span class="n">a</span><span class="p">.</span><span class="n">abs</span><span class="p">());</span>   <span class="c1">// NoSuchMethodError: The method &#39;abs&#39; was called on null.
</span><span class="c1"></span>
<span class="n">print</span><span class="p">(</span><span class="n">a</span><span class="o">?</span><span class="p">.</span><span class="n">abs</span><span class="p">());</span>  <span class="c1">// null
</span><span class="c1"></span><span class="n">a</span> <span class="o">=</span> <span class="o">-</span><span class="m">100</span><span class="p">;</span>
<span class="n">print</span><span class="p">(</span><span class="n">a</span><span class="o">?</span><span class="p">.</span><span class="n">abs</span><span class="p">());</span>  <span class="c1">// 100
</span></code></pre></td></tr></table>
</div>
</div><ul>
<li>链式调用符: <code>..</code> 链式调用对象的多个方法或属性, 最终会返回对象本身</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="kd">class</span> <span class="nc">Book</span> <span class="p">{</span>
  <span class="kt">String</span> <span class="n">name</span><span class="p">;</span>
  <span class="kt">double</span> <span class="n">price</span><span class="p">;</span>

  <span class="kt">String</span> <span class="n">getSequence</span><span class="p">()</span> <span class="o">=&gt;</span> <span class="s2">&#34;</span><span class="si">$</span><span class="n">name</span><span class="s2">-</span><span class="si">$</span><span class="n">price</span><span class="s2">&#34;</span><span class="p">;</span>
<span class="p">}</span>

<span class="kd">final</span> <span class="n">book</span> <span class="o">=</span> <span class="n">Book</span><span class="p">()</span>
    <span class="p">..</span><span class="n">name</span> <span class="o">=</span> <span class="s2">&#34;Dartlang&#34;</span>
    <span class="p">..</span><span class="n">price</span> <span class="o">=</span> <span class="m">100.0</span>
    <span class="p">..</span><span class="n">getSequence</span><span class="p">();</span>

<span class="n">print</span><span class="p">(</span><span class="n">book</span><span class="p">);</span> <span class="c1">//Instance of &#39;Book&#39;
</span></code></pre></td></tr></table>
</div>
</div><h2 id="class">Class</h2>
<h3 id="构造函数">构造函数</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="kd">class</span> <span class="nc">Book</span> <span class="p">{</span>
  <span class="kt">String</span> <span class="n">name</span><span class="p">;</span>
  <span class="kt">double</span> <span class="n">price</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><ul>
<li>默认构造函数, 没有任何参数</li>
<li>带参数构造函数</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="n">Book</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="n">name</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="n">price</span><span class="p">);</span>
<span class="c1">// 等价于
</span><span class="c1"></span><span class="n">Book</span><span class="p">(</span><span class="kt">String</span> <span class="n">name</span><span class="p">,</span> <span class="kt">double</span> <span class="n">price</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">this</span><span class="p">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span><span class="p">;</span>
  <span class="k">this</span><span class="p">.</span><span class="n">price</span> <span class="o">=</span> <span class="n">price</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><ul>
<li>命名构造函数</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="n">Book</span><span class="p">.</span><span class="n">fromJson</span><span class="p">(</span><span class="n">Map</span><span class="o">&lt;</span><span class="kt">String</span><span class="p">,</span> <span class="kt">dynamic</span><span class="o">&gt;</span> <span class="n">json</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">this</span><span class="p">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">json</span><span class="p">[</span><span class="s1">&#39;name&#39;</span><span class="p">];</span>
  <span class="k">this</span><span class="p">.</span><span class="n">price</span> <span class="o">=</span> <span class="n">json</span><span class="p">[</span><span class="s1">&#39;price&#39;</span><span class="p">];</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><ul>
<li>初始化列表</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="n">Book</span><span class="p">.</span><span class="n">fromJson</span><span class="p">(</span><span class="n">Map</span><span class="o">&lt;</span><span class="kt">String</span><span class="p">,</span> <span class="kt">dynamic</span><span class="o">&gt;</span> <span class="n">json</span><span class="p">)</span>
  <span class="o">:</span> <span class="n">name</span> <span class="o">=</span> <span class="n">json</span><span class="p">[</span><span class="s1">&#39;name&#39;</span><span class="p">],</span>
    <span class="n">price</span> <span class="o">=</span> <span class="n">json</span><span class="p">[</span><span class="s1">&#39;price&#39;</span><span class="p">]{}</span>
</code></pre></td></tr></table>
</div>
</div><ul>
<li>重定向构造函数: 调用其他构造函数</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="n">Book</span><span class="p">.</span><span class="n">fromJson</span><span class="p">(</span><span class="n">Map</span><span class="o">&lt;</span><span class="kt">String</span><span class="p">,</span> <span class="kt">dynamic</span><span class="o">&gt;</span> <span class="n">json</span><span class="p">)</span> <span class="o">:</span><span class="k">this</span><span class="p">(</span><span class="n">json</span><span class="p">[</span><span class="s1">&#39;name&#39;</span><span class="p">],</span> <span class="n">json</span><span class="p">[</span><span class="s1">&#39;price&#39;</span><span class="p">]);</span>
</code></pre></td></tr></table>
</div>
</div><ul>
<li>常量构造函数: 返回一个编译期常量对象, 这种情况下属性必须是<code>final</code>的, 构造函数必须是 <code>const</code> 的</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="kd">class</span> <span class="nc">Book</span> <span class="p">{</span>
  <span class="kd">final</span> <span class="kt">String</span> <span class="n">name</span><span class="p">;</span>
  <span class="kd">final</span> <span class="kt">double</span> <span class="n">price</span><span class="p">;</span>

  <span class="kd">const</span> <span class="n">Book</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="n">name</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="n">price</span><span class="p">);</span>

  <span class="kd">static</span> <span class="kd">final</span> <span class="n">Book</span> <span class="n">origin</span> <span class="o">=</span> <span class="kd">const</span> <span class="n">Book</span><span class="p">(</span><span class="s2">&#34;dart&#34;</span><span class="p">,</span> <span class="m">100.0</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><ul>
<li>工厂构造函数: 可用于不一定返回新对象的情况, 比如:
<ul>
<li>从缓存返回</li>
<li>返回一个子类对象</li>
<li>单例模式</li>
</ul>
</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="c1">// 单例模式例子
</span><span class="c1"></span><span class="kd">class</span> <span class="nc">SingleClass</span> <span class="p">{</span>
  <span class="kd">static</span> <span class="n">SingleClass</span> <span class="n">_instance</span><span class="p">;</span>

  <span class="n">SingleClass</span><span class="p">.</span><span class="n">_inner</span><span class="p">();</span>

  <span class="kd">factory</span> <span class="n">SingleClass</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">_instance</span> <span class="o">==</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">_instance</span> <span class="o">=</span> <span class="n">SingleClass</span><span class="p">.</span><span class="n">_inner</span><span class="p">();</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">_instance</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">}</span>

<span class="c1">// 调用
</span><span class="c1"></span><span class="kd">final</span> <span class="n">a</span> <span class="o">=</span> <span class="n">SingleClass</span><span class="p">();</span>
<span class="kd">final</span> <span class="n">b</span> <span class="o">=</span> <span class="n">SingleClass</span><span class="p">();</span>
<span class="n">print</span><span class="p">(</span><span class="n">a</span> <span class="o">==</span> <span class="n">b</span><span class="p">);</span> <span class="c1">// true
</span></code></pre></td></tr></table>
</div>
</div><h3 id="方法">方法</h3>
<h4 id="实例方法">实例方法</h4>
<p>与 Java 类似, 对象都会拥有实例方法</p>
<h4 id="geter-seter">geter seter</h4>
<ul>
<li>会隐式的为类的属性提供 <code>getter</code> 和 <code>setter</code> 方法.</li>
<li>可通过 <code>get</code> <code>set</code> 关键字提供额外的 <code>getter</code> 和 <code>setter</code>(参照上面关键字部分)</li>
</ul>
<h4 id="抽象方法-abstract-method">抽象方法 abstract method</h4>
<p>抽象方法只能存在抽象类中, 且子类(如果子类不是抽象类)必须实现抽象方法</p>
<h4 id="抽象类">抽象类</h4>
<p>与 Java 类似</p>
<h4 id="隐式接口">隐式接口</h4>
<p>Dart 为每个类隐式定义了一个接口, 接口包含了类的所有属性和实例方法. 如果你想提供和一个类相同的能力, 而又不想继承它, 那可以直接使用 <code>implements</code> 实现它即可.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="kd">class</span> <span class="nc">Person</span> <span class="p">{</span>
  <span class="c1">// 会包含在隐式接口中, 因为 name 是 final, 所以只会隐式生成 getter, 则实现接口的类也应该提供一个 name 的 getter 方法
</span><span class="c1"></span>  <span class="kd">final</span> <span class="kt">String</span> <span class="n">name</span><span class="p">;</span>

  <span class="c1">// 会包含在隐式接口中, 因为 age 不是 final, 所以会隐式生成 getter 和 setter,  则实现接口的类也应该提供 age 的 getter 和 setter 方法
</span><span class="c1"></span>  <span class="kt">int</span> <span class="n">age</span><span class="p">;</span>

  <span class="c1">// 不会包含在隐式接口中
</span><span class="c1"></span>  <span class="n">Person</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="n">name</span><span class="p">);</span>

  <span class="c1">// 会包含在隐式接口中
</span><span class="c1"></span>  <span class="kt">String</span> <span class="n">greet</span><span class="p">(</span><span class="kt">String</span> <span class="n">who</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="s2">&#34;Hi </span><span class="si">$</span><span class="n">who</span><span class="s2">, I&#39;m </span><span class="si">$</span><span class="n">name</span><span class="s2">&#34;</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// 继承自 Person, 用于 Person 类的所有
</span><span class="c1"></span><span class="kd">class</span> <span class="nc">Man</span> <span class="kd">extends</span> <span class="n">Person</span> <span class="p">{</span>
  <span class="n">Man</span><span class="p">(</span><span class="kt">String</span> <span class="n">name</span><span class="p">)</span> <span class="o">:</span> <span class="k">super</span><span class="p">(</span><span class="n">name</span><span class="p">);</span>
<span class="p">}</span>

<span class="c1">// 实现了 Person 类的隐式接口, 需要实现包含在接口中的方法
</span><span class="c1"></span><span class="kd">class</span> <span class="nc">Women</span> <span class="kd">implements</span> <span class="n">Person</span> <span class="p">{</span>

  <span class="kt">String</span> <span class="n">nickName</span><span class="p">;</span>

  <span class="err">@</span><span class="n">override</span>
  <span class="kt">String</span> <span class="kd">get</span> <span class="n">name</span> <span class="o">=&gt;</span> <span class="n">nickName</span><span class="p">;</span>

  <span class="err">@</span><span class="n">override</span>
  <span class="kt">String</span> <span class="n">greet</span><span class="p">(</span><span class="kt">String</span> <span class="n">who</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="s2">&#34;Hi </span><span class="si">$</span><span class="n">who</span><span class="s2">. Do you know who I am&#34;</span><span class="p">;</span>

  <span class="err">@</span><span class="n">override</span>
  <span class="kt">int</span> <span class="kd">get</span> <span class="n">age</span> <span class="o">=&gt;</span> <span class="m">0</span><span class="p">;</span>

  <span class="err">@</span><span class="n">override</span>
  <span class="kt">void</span> <span class="kd">set</span> <span class="n">age</span><span class="p">(</span><span class="kt">int</span> <span class="n">_age</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">this</span><span class="p">.</span><span class="n">age</span> <span class="o">=</span> <span class="n">_age</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><h4 id="使用-mixin">使用 mixin</h4>
<p><a href="/2019/03/15/Dart%E4%B8%AD%E7%9A%84Mixin/#more">请移步 &ldquo;Dart 中的Mixin&rdquo;</a></p>
<h4 id="类变量和方法">类变量和方法</h4>
<ul>
<li>使用 <code>static</code> 声明类变量, 与Java 不同, 类变量只能通过类调用, 不能通过实例调用</li>
<li>使用 <code>static</code> 声明类方法, 与Java 不同, 类方法只能通过类调用, 不能通过实例调用</li>
</ul>
<h2 id="泛型">泛型</h2>
<p>基本使用与 Java 类似, 但有一个最大不同, Dart 的泛型在运行时不会被擦除, 在运行时可以知道泛型的类型.</p>
<p>Dart:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="kd">class</span> <span class="nc">Wrap</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="p">{</span>
  <span class="kd">final</span> <span class="n">T</span> <span class="n">data</span><span class="p">;</span>

  <span class="n">Wrap</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="n">data</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
  <span class="kd">final</span> <span class="n">data</span> <span class="o">=</span> <span class="n">Wrap</span><span class="o">&lt;</span><span class="kt">String</span><span class="o">&gt;</span><span class="p">(</span><span class="s2">&#34;ABC&#34;</span><span class="p">);</span>
  <span class="n">print</span><span class="p">(</span><span class="n">data</span> <span class="k">is</span> <span class="n">Wrap</span><span class="o">&lt;</span><span class="kt">String</span><span class="o">&gt;</span><span class="p">);</span> <span class="c1">// true
</span><span class="c1"></span>  <span class="n">print</span><span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="n">runtimeType</span><span class="p">);</span> <span class="c1">// Wrap&lt;String&gt;
</span><span class="c1"></span><span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><p>Java:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-java" data-lang="java"><span class="kd">class</span> <span class="nc">Wrap</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="o">{</span>
    <span class="n">T</span> <span class="n">data</span><span class="o">;</span>

    <span class="kd">public</span> <span class="nf">Wrap</span><span class="o">(</span><span class="n">T</span> <span class="n">data</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">this</span><span class="o">.</span><span class="na">data</span> <span class="o">=</span> <span class="n">data</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">}</span>

<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="n">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="o">{</span>
    <span class="n">Wrap</span><span class="o">&lt;</span><span class="n">String</span><span class="o">&gt;</span> <span class="n">data</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Wrap</span><span class="o">&lt;&gt;(</span><span class="s">&#34;ABC&#34;</span><span class="o">);</span>    
    <span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">data</span> <span class="k">instanceof</span> <span class="n">Wrap</span><span class="o">&lt;</span><span class="n">String</span><span class="o">&gt;);</span> <span class="c1">// 不支持的操作
</span><span class="c1"></span>    <span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">data</span><span class="o">.</span><span class="na">getClass</span><span class="o">().</span><span class="na">getName</span><span class="o">());</span> <span class="c1">// Wrap
</span><span class="c1"></span><span class="o">}</span>
</code></pre></td></tr></table>
</div>
</div><h2 id="异步">异步</h2>
<h3 id="创建异步方法">创建异步方法</h3>
<p>返回 <code>Future</code> 或 <code>Stream</code> 的方法就是异步方法, 不需要等待这些方法中进行的耗时操作就可以返回.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="kt">void</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
  <span class="n">print</span><span class="p">(</span><span class="s2">&#34;start&#34;</span><span class="p">);</span>
  <span class="n">asyncGetNum</span><span class="p">();</span>
  <span class="n">print</span><span class="p">(</span><span class="s2">&#34;end&#34;</span><span class="p">);</span>
<span class="p">}</span>

<span class="n">Future</span><span class="o">&lt;</span><span class="kt">void</span><span class="o">&gt;</span> <span class="n">asyncGetNum</span><span class="p">()</span> <span class="p">{</span>
  <span class="k">return</span> <span class="n">Future</span><span class="p">.</span><span class="n">delayed</span><span class="p">(</span><span class="n">Duration</span><span class="p">(</span><span class="nl">seconds:</span> <span class="m">1</span><span class="p">),</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="n">print</span><span class="p">(</span><span class="s2">&#34;async&#34;</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><p>输出:</p>
<pre><code>start
end
async
</code></pre><h3 id="等待-future-的结果">等待 Future 的结果</h3>
<ul>
<li>在 <code>async</code> 方法中使用 <code>await</code> 等待一个 <code>Future</code> 执行结束</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="kt">void</span> <span class="n">printNun</span><span class="p">()</span> <span class="kd">async</span> <span class="p">{</span>
  <span class="kd">final</span> <span class="kt">num</span> <span class="o">=</span> <span class="kd">await</span> <span class="n">asyncGetNum</span><span class="p">();</span>
  <span class="n">print</span><span class="p">(</span><span class="kt">num</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><ul>
<li>使用 <code>Future</code> 的 <code>then</code> 接口</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="kt">void</span> <span class="n">printNun</span><span class="p">(){</span>
  <span class="kd">final</span> <span class="n">Future</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">numFuture</span> <span class="o">=</span> <span class="n">asyncGetNum</span><span class="p">();</span>
  <span class="n">numFuture</span><span class="p">.</span><span class="n">then</span><span class="p">((</span><span class="kt">num</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="n">print</span><span class="p">(</span><span class="kt">num</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><h4 id="捕获异常">捕获异常</h4>
<p>抛出异常:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="n">Future</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">asyncGetNum</span><span class="p">()</span> <span class="p">{</span>
  <span class="k">return</span> <span class="n">Future</span><span class="p">.</span><span class="n">delayed</span><span class="p">(</span><span class="n">Duration</span><span class="p">(</span><span class="nl">seconds:</span> <span class="m">1</span><span class="p">),</span> <span class="p">()</span> <span class="p">{</span>
    <span class="k">throw</span> <span class="n">Exception</span><span class="p">(</span><span class="s2">&#34;exception&#34;</span><span class="p">);</span>
    <span class="k">return</span> <span class="m">100</span><span class="p">;</span>
  <span class="p">});</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><ul>
<li>使用 <code>try</code> <code>catch</code> 捕获</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="k">try</span> <span class="p">{</span>
  <span class="kd">final</span> <span class="kt">num</span> <span class="o">=</span> <span class="kd">await</span> <span class="n">asyncGetNum</span><span class="p">();</span>
  <span class="n">print</span><span class="p">(</span><span class="kt">num</span><span class="p">);</span>
<span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="n">e</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">print</span><span class="p">(</span><span class="n">e</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><ul>
<li>使用 <code>Future</code> 的 <code>catchError</code> 捕获</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="kd">final</span> <span class="n">Future</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">numFuture</span> <span class="o">=</span> <span class="n">asyncGetNum</span><span class="p">();</span>
<span class="n">numFuture</span><span class="p">.</span><span class="n">then</span><span class="p">((</span><span class="kt">num</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="n">print</span><span class="p">(</span><span class="kt">num</span><span class="p">)).</span><span class="n">catchError</span><span class="p">((</span><span class="n">error</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="n">print</span><span class="p">(</span><span class="n">error</span><span class="p">));</span>
</code></pre></td></tr></table>
</div>
</div><h3 id="等待-stream-的结果">等待 Stream 的结果</h3>
<p>使用 Stream:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="n">Stream</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">streamNum</span><span class="p">()</span> <span class="p">{</span>
  <span class="k">return</span> <span class="n">Stream</span><span class="p">.</span><span class="n">fromIterable</span><span class="p">([</span><span class="m">1</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="m">3</span><span class="p">,</span> <span class="m">4</span><span class="p">,</span> <span class="m">5</span><span class="p">]);</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><ul>
<li>在 <code>async</code> 方法中使用 <code>await for</code> 等待一个循环</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="kt">void</span> <span class="n">printNun</span><span class="p">()</span> <span class="kd">async</span> <span class="p">{</span>
  <span class="kd">await</span> <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="k">in</span> <span class="n">streamNum</span><span class="p">())</span> <span class="p">{</span>
    <span class="n">print</span><span class="p">(</span><span class="n">i</span><span class="p">);</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><ul>
<li>使用 <code>Stream</code> 的 <code>listen</code> 接口</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="kt">void</span> <span class="n">printNun</span><span class="p">()</span> <span class="p">{</span>
  <span class="n">streamNum</span><span class="p">().</span><span class="n">listen</span><span class="p">((</span><span class="n">i</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="n">print</span><span class="p">(</span><span class="n">i</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><h2 id="generators-生成器">Generators 生成器</h2>
<p>当需要延迟产生序列值时(不会在内存储存整个序列, 只有当需要下一个值时才计算一下个值), 可以使用 <code>generator</code> 方法, <code>Dart</code> 支持两种 generator 方法:</p>
<ul>
<li>同步的生成器: 返回 <code>Iterable</code> 对象</li>
<li>异步的生成器: 返回 <code>Stream</code> 对象</li>
</ul>
<p>实现同步生成器:</p>
<ul>
<li>方法返回 <code>Interable</code></li>
<li>方法使用 <code>sync*</code> 标记</li>
<li>使用 <code>yield</code> 抛出值</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="n">Iterable</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">naturalsTo</span><span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="kd">sync</span><span class="o">*</span> <span class="p">{</span>
  <span class="kt">int</span> <span class="n">k</span> <span class="o">=</span> <span class="m">0</span><span class="p">;</span>
  <span class="k">while</span> <span class="p">(</span><span class="n">k</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">print</span><span class="p">(</span><span class="s2">&#34;produce&#34;</span><span class="p">);</span>
    <span class="kd">yield</span> <span class="n">k</span><span class="o">++</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><p>实现异步生成器:</p>
<ul>
<li>方法返回 <code>Stream</code></li>
<li>方法使用 <code>async*</code> 标记</li>
<li>使用 <code>yield</code> 抛出值</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="n">Stream</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">asyncNaturalsTo</span><span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="kd">async</span><span class="o">*</span> <span class="p">{</span>
  <span class="kt">int</span> <span class="n">k</span> <span class="o">=</span> <span class="m">0</span><span class="p">;</span>
  <span class="k">while</span> <span class="p">(</span><span class="n">k</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">print</span><span class="p">(</span><span class="s2">&#34;async produce&#34;</span><span class="p">);</span>
    <span class="kd">yield</span> <span class="n">k</span><span class="o">++</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><p>如果逻辑是递归的, 可以使用 <code>yield*</code> 优化性能:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="n">Iterable</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">naturalsDownFrom</span><span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="kd">sync</span><span class="o">*</span> <span class="p">{</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">n</span> <span class="o">&gt;</span> <span class="m">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="kd">yield</span> <span class="n">n</span><span class="p">;</span>
    <span class="kd">yield</span><span class="o">*</span> <span class="n">naturalsDownFrom</span><span class="p">(</span><span class="n">n</span> <span class="o">-</span> <span class="m">1</span><span class="p">);</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><h2 id="callable-class">Callable class</h2>
<p>为一个类实现 <code>call</code> 方法, 该类就能像一个方法一样被调用.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="kd">class</span> <span class="nc">Dog</span> <span class="p">{</span>
  <span class="kt">void</span> <span class="n">call</span><span class="p">()</span> <span class="o">=&gt;</span> <span class="n">print</span><span class="p">(</span><span class="s2">&#34;wang wang&#34;</span><span class="p">);</span>
<span class="p">}</span>

<span class="kd">final</span> <span class="n">dog</span> <span class="o">=</span> <span class="n">Dog</span><span class="p">();</span>
<span class="n">dog</span><span class="p">();</span> <span class="c1">// wang wang
</span></code></pre></td></tr></table>
</div>
</div><h2 id="isolates">Isolates</h2>
<p>在 Dart 中, 程序运行在自己的 <code>Isolate</code> 中, 类似 Java 里的 <code>Thread</code>, 但是 <code>Isolate</code> 彼此独立, 内存不能互相访问, 每个 <code>Isolate</code> 有自己的内存堆.</p>
<p><a href="/2019/03/15/Dart%E4%B8%AD%E7%9A%84%E5%BC%82%E6%AD%A5%E7%BC%96%E7%A8%8B/">请移步 &ldquo;Dart 中的异步&rdquo;</a></p>
<h2 id="typedefs-类型定义">Typedefs 类型定义</h2>
<p>为方法定义一个类型, 当方法被一个变量引用时, 这个类型信息也会能被使用. 比如:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="kd">class</span> <span class="nc">SortedCollection</span> <span class="p">{</span>
  <span class="n">Function</span> <span class="n">compare</span><span class="p">;</span>

  <span class="n">SortedCollection</span><span class="p">(</span><span class="kt">int</span> <span class="n">f</span><span class="p">(</span><span class="kt">Object</span> <span class="n">a</span><span class="p">,</span> <span class="kt">Object</span> <span class="n">b</span><span class="p">))</span> <span class="p">{</span>
    <span class="n">compare</span> <span class="o">=</span> <span class="n">f</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">sort</span><span class="p">(</span><span class="kt">Object</span> <span class="n">a</span><span class="p">,</span> <span class="kt">Object</span> <span class="n">b</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="m">0</span><span class="p">;</span>

<span class="kt">void</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
  <span class="n">SortedCollection</span> <span class="n">coll</span> <span class="o">=</span> <span class="n">SortedCollection</span><span class="p">(</span><span class="n">sort</span><span class="p">);</span>
  <span class="c1">// 只能知道 compare 是一个方法, 但是不能知道它具体是什么方法
</span><span class="c1"></span>  <span class="k">assert</span><span class="p">(</span><span class="n">coll</span><span class="p">.</span><span class="n">compare</span> <span class="k">is</span> <span class="n">Function</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><p>使用 <code>typedef</code>:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="kd">typedef</span> <span class="n">Compare</span> <span class="o">=</span> <span class="kt">int</span> <span class="n">Function</span><span class="p">(</span><span class="kt">Object</span> <span class="n">a</span><span class="p">,</span> <span class="kt">Object</span> <span class="n">b</span><span class="p">);</span>

<span class="kd">class</span> <span class="nc">SortedCollection</span> <span class="p">{</span>
  <span class="n">Compare</span> <span class="n">compare</span><span class="p">;</span>

  <span class="n">SortedCollection</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="n">compare</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">sort</span><span class="p">(</span><span class="kt">Object</span> <span class="n">a</span><span class="p">,</span> <span class="kt">Object</span> <span class="n">b</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="m">0</span><span class="p">;</span>

<span class="kt">void</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
  <span class="n">SortedCollection</span> <span class="n">coll</span> <span class="o">=</span> <span class="n">SortedCollection</span><span class="p">(</span><span class="n">sort</span><span class="p">);</span>
  <span class="c1">// 可以知道 compare 是一个方法, 也能知道它具体是什么类型的方法
</span><span class="c1"></span>  <span class="k">assert</span><span class="p">(</span><span class="n">coll</span><span class="p">.</span><span class="n">compare</span> <span class="k">is</span> <span class="n">Function</span><span class="p">);</span>
  <span class="k">assert</span><span class="p">(</span><span class="n">coll</span><span class="p">.</span><span class="n">compare</span> <span class="k">is</span> <span class="n">Compare</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><h2 id="原数据-metadata">原数据 Metadata</h2>
<p>类似 Java 中的注解. 可以在运行时通过反射拿到 <code>Metadata</code>.</p>
<p>定义自己的注解:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="k">library</span> <span class="n">todo</span><span class="p">;</span>

<span class="kd">class</span> <span class="nc">Todo</span> <span class="p">{</span>
  <span class="kd">final</span> <span class="kt">String</span> <span class="n">who</span><span class="p">;</span>
  <span class="kd">final</span> <span class="kt">String</span> <span class="n">what</span><span class="p">;</span>

  <span class="kd">const</span> <span class="n">Todo</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="n">who</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="n">what</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-dart" data-lang="dart"><span class="err">@</span><span class="n">Todo</span><span class="p">(</span><span class="s2">&#34;me&#34;</span><span class="p">,</span> <span class="s2">&#34;fix something&#34;</span><span class="p">)</span>
<span class="kt">void</span> <span class="n">doSomething</span><span class="p">()</span> <span class="p">{}</span>
</code></pre></td></tr></table>
</div>
</div>
    </article>
    
    
<script defer src="/js/clipboard.min.1626706afc88d95ebe1173b553ec732c6dc82a576989315fdf5e7779af738a44.js"></script>

<script defer src="/js/helper/prev.min.js"></script>

<script defer src="/js/helper/prop.min.js"></script>
<script>
  'use strict';
  document.addEventListener('DOMContentLoaded', function () {
    
    var clipInit = false;
    var preChromaElem = document.querySelectorAll('pre.chroma');
    var langCodeElem = document.querySelectorAll('.language-code');
    var dollarCodeElem = document.querySelectorAll('div.language-\\$');
    var gtCodeElem = document.querySelectorAll('div.language-\\>');

    var makeClipboard = function(elem) {
      var code = elem,
          text = elem.textContent;
        
      if (text.length > 15) {
        if (!clipInit) {
          var text, clip = new ClipboardJS('.copy-to-clipboard', {
            text: function (trigger) {
              var codeElem = prev(trigger).querySelectorAll('code');
              if (codeElem.length > 1) {
                text = prev(trigger).querySelector('code[class^="language-"]').textContent;
              } else {
                text = prev(trigger).querySelector('code').textContent;
              }

              return text.replace(/^\$\s/gm, '');
            }
          });

          var inPre;
          clip.on('success', function (e) {
            e.clearSelection();
            inPre = prop(e.trigger.parentNode, 'tagName') == 'PRE';
            e.trigger.setAttribute('aria-label', 'Copied to clipboard!');
            e.trigger.classList.add('tooltipped');
            e.trigger.classList.add('tooltipped-w');
          });

          clip.on('error', function (e) {
            inPre = prop(e.trigger.parentNode, 'tagName') == 'PRE';
            e.trigger.setAttribute('aria-label', e.action.toString());
            e.trigger.classList.add('tooltipped');
            e.trigger.classList.add('tooltipped-w');
          });

          clipInit = true;
        }

        var notAllowedClass = ['language-mermaid', 'language-viz', 'language-wave', 'language-chart', 'language-msc', 'language-flowchart'];
        var isNotAllowedIncluded = false;
        var curClassName = code.getAttribute('class');

        for (var i = 0; i < notAllowedClass.length; i++) {
          if (curClassName && curClassName.startsWith(notAllowedClass[i])) {
            isNotAllowedIncluded = true;
            break;
          }
        }

        if (!isNotAllowedIncluded) {
          if (curClassName) {
            var newClipboardElem = document.createElement('span');
            newClipboardElem.setAttribute('class', 'copy-to-clipboard');
            newClipboardElem.setAttribute('title', 'Copy to clipboard');
            elem.parentNode.parentNode.insertBefore(newClipboardElem, elem.parentNode.nextElementSibling);
          }
        }
      }
    }

    var makeSymbolClipboard = function(elem) {
      var clipboardSpan = document.createElement('span');
      clipboardSpan.setAttribute('class', 'copy-to-clipboard');
      clipboardSpan.setAttribute('title', 'Copy to clipboard');
      elem.parentNode.parentNode.insertBefore(clipboardSpan, elem.parentNode.nextElementSibling);
    }

    preChromaElem ? 
    preChromaElem.forEach(function(elem) {
      elem.querySelectorAll('code').forEach(function(codeElem) {
        makeClipboard(codeElem);
      });
    }) : null;
    
    langCodeElem ? 
    langCodeElem.forEach(function(elem) {
      elem.querySelectorAll('code').forEach(function (codeElem) {
        makeClipboard(codeElem);
      });
    }) : null;

    dollarCodeElem ? 
    dollarCodeElem.forEach(function(elem) {
      elem.querySelectorAll('code').forEach(function (codeElem) {
        makeSymbolClipboard(codeElem);
      });
    }) : null;

    gtCodeElem ?
    gtCodeElem.forEach(function(elem) {
      elem.querySelectorAll('code').forEach(function (codeElem) {
        makeSymbolClipboard(codeElem);
      });
    }) : null;
    
  });
</script>
    <script>
  'use strict';
  
  function wrap(el, wrapper) {
    el.parentNode.insertBefore(wrapper, el);
    wrapper.appendChild(el);
  }

  (function () {
    var singleContentsElem = document.querySelector('.single__contents');
    singleContentsElem ? 
    singleContentsElem.querySelectorAll('pre > code').forEach(function(elem) {
      var dataLang = elem.getAttribute('data-lang');
      var dataLangWrapper = document.createElement('div');
      var code = null;
      var codeTitle = null;

      if (dataLang && dataLang.includes(':')) {
        code = dataLang.split(':')[0];
        codeTitle = dataLang.split(':')[1];

        dataLangWrapper.className = 'language-' + code;
        dataLangWrapper.setAttribute('data-lang', codeTitle);

        elem.className = 'language-' + code;
        elem.setAttribute('data-lang', codeTitle);
        elem.setAttribute('id', codeTitle);
      } else if (!dataLang) {
        dataLangWrapper.setAttribute('data-lang', 'Code');
        dataLangWrapper.className = 'language-code';
      }

      if (!dataLang || codeTitle) {
        wrap(elem.parentNode, dataLangWrapper);
      }

    }) : null;
  })();

  var langCodeElem = document.querySelectorAll('.language-code');
  langCodeElem ? langCodeElem.forEach(function (elem) {
    var newElem = document.createElement('span');
    newElem.className = 'copy-to-clipboard';
    newElem.setAttribute('title', 'Copy to clipboard');
    elem.append(newElem);
  }) : null;
  

  

  
  var dollarCodeElem = document.querySelectorAll('div.language-\\$');
  var gtCodeElem = document.querySelectorAll('div.language-\\>');

  dollarCodeElem ?
  dollarCodeElem.forEach(function(elem) {
    var lnts = elem.parentNode.parentNode ? elem.parentNode.parentNode.querySelectorAll('.lnt') : null;
    lnts ? 
    lnts.forEach(function(lnt) {
      lnt.innerHTML = '$<br/>';
    }) : null;
  }) : null;

  gtCodeElem ?
  gtCodeElem.forEach(function(elem) {
    var lnts = elem.parentNode.parentNode ? elem.parentNode.parentNode.querySelectorAll('.lnt') : null;
    lnts ? 
    lnts.forEach(function(lnt) {
      lnt.innerHTML = '><br/>';
    }) : null;
  }) : null;
  
</script>
    

    
<div class="donation">
  <div class="donation__message">
    Support the author with
  </div>
  <div class="donation__icons">
    
    
    
    <div class="donation__item donation__dropup" title="alipay" aria-label="alipay" data-type="donation">
      <svg fill="#000000" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="35" height="35"><path fill="#00A1E9" d="M 5 5 L 5 27 L 27 27 L 27 5 L 5 5 z M 7 7 L 25 7 L 25 18.931641 L 18.929688 16.775391 C 19.528069 15.604874 19.872428 14.319295 20 13 L 17 13 L 17 12 L 21 12 L 21 11 L 17 11 L 17 9 L 15 9 L 15 11 L 10 11 L 10 12 L 15 12 L 15 13 L 11 13 L 11 14 L 18.042969 14 C 17.874523 14.798238 17.595556 15.553113 17.226562 16.220703 C 17.067744 16.141588 16.909631 16.060926 16.748047 15.988281 C 16.275047 15.769281 15.785203 15.594937 15.283203 15.460938 C 14.281203 15.185937 13.248844 15.029953 12.214844 15.001953 C 11.955844 14.994953 11.6955 15.005813 11.4375 15.007812 C 11.1535 15.021812 10.861031 15.045953 10.582031 15.126953 C 10.020031 15.271953 9.5026563 15.571516 9.0976562 15.978516 C 8.2506563 16.776516 7.9028281 17.969375 8.0488281 19.109375 C 8.1738281 20.285375 9.0837031 21.364953 10.220703 21.751953 C 10.770703 21.960953 11.416641 22.039422 11.931641 21.982422 C 12.202641 21.976422 12.472188 21.956297 12.742188 21.904297 C 13.013188 21.866297 13.281922 21.822234 13.544922 21.740234 C 14.607922 21.469234 15.606062 20.931031 16.414062 20.207031 C 16.818062 19.845031 17.187578 19.452297 17.517578 19.029297 C 17.673578 18.811297 17.84375 18.601328 17.96875 18.361328 C 17.986598 18.324421 17.999073 18.284503 18.017578 18.248047 L 25 22.044922 L 25 25 L 7 25 L 7 7 z M 11.427734 16.341797 L 12.109375 16.388672 C 13.020375 16.473672 13.909156 16.711516 14.785156 16.978516 C 15.220156 17.122516 15.651125 17.283172 16.078125 17.451172 C 16.169125 17.488172 16.257656 17.530313 16.347656 17.570312 C 16.265656 17.685312 16.183703 17.800109 16.095703 17.912109 C 15.835703 18.249109 15.532328 18.544703 15.236328 18.845703 C 14.636328 19.436703 13.928094 19.918141 13.121094 20.244141 C 12.921094 20.332141 12.710094 20.385547 12.496094 20.435547 C 12.284094 20.499547 12.06575 20.534594 11.84375 20.558594 C 11.37975 20.644594 11.008375 20.634062 10.609375 20.539062 C 9.834375 20.367062 9.1521562 19.755547 9.0351562 18.935547 C 8.8801563 18.121547 9.246 17.233016 9.875 16.791016 C 10.182 16.559016 10.534719 16.428234 10.886719 16.365234 C 11.064719 16.330234 11.241734 16.336797 11.427734 16.341797 z"/></svg>
      <div class="donation__dropup--content">
        <img data-src="/images/donation/alipay.png" alt="alipay QR Code"
          src="data:image/svg+xml,%0A%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath fill='none' d='M0 0h24v24H0V0z'/%3E%3Cpath fill='%23aaa' d='M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-1 16H6c-.55 0-1-.45-1-1V6c0-.55.45-1 1-1h12c.55 0 1 .45 1 1v12c0 .55-.45 1-1 1zm-4.44-6.19l-2.35 3.02-1.56-1.88c-.2-.25-.58-.24-.78.01l-1.74 2.23c-.26.33-.02.81.39.81h8.98c.41 0 .65-.47.4-.8l-2.55-3.39c-.19-.26-.59-.26-.79 0z'/%3E%3C/svg%3E"
          class="lazyload" />
      </div>
    </div>
    
    
    
    
    
    
    
    
    
    
    
    
    
    <div class="donation__item donation__dropup" title="wechat" aria-label="wechat" data-type="donation">
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="35" height="35"><path fill="#8BC34A" d="M18,6C9.2,6,2,12,2,19.5c0,4.3,2.3,8,6,10.5l-2,6l6.3-3.9C14,32.7,16,33,18,33c8.8,0,16-6,16-13.5C34,12,26.8,6,18,6z"/><path fill="#7CB342" d="M20,29c0-6.1,5.8-11,13-11c0.3,0,0.6,0,0.9,0c-0.1-0.7-0.3-1.4-0.5-2c-0.1,0-0.3,0-0.4,0c-8.3,0-15,5.8-15,13c0,1.4,0.3,2.7,0.7,4c0.7,0,1.4-0.1,2.1-0.2C20.3,31.6,20,30.3,20,29z"/><path fill="#CFD8DC" d="M46,29c0-6.1-5.8-11-13-11c-7.2,0-13,4.9-13,11s5.8,11,13,11c1.8,0,3.5-0.3,5-0.8l5,2.8l-1.4-4.8C44.3,35.2,46,32.3,46,29z"/><path fill="#33691E" d="M14,15c0,1.1-0.9,2-2,2s-2-0.9-2-2s0.9-2,2-2S14,13.9,14,15z M24,13c-1.1,0-2,0.9-2,2s0.9,2,2,2s2-0.9,2-2S25.1,13,24,13z"/><path fill="#546E7A" d="M30,26.5c0,0.8-0.7,1.5-1.5,1.5S27,27.3,27,26.5s0.7-1.5,1.5-1.5S30,25.7,30,26.5z M37.5,25c-0.8,0-1.5,0.7-1.5,1.5s0.7,1.5,1.5,1.5s1.5-0.7,1.5-1.5S38.3,25,37.5,25z"/></svg>
      <div class="donation__dropup--content">
        <img data-src="/images/donation/wechatpay.png" alt="wechat QR Code"
          src="data:image/svg+xml,%0A%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath fill='none' d='M0 0h24v24H0V0z'/%3E%3Cpath fill='%23aaa' d='M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-1 16H6c-.55 0-1-.45-1-1V6c0-.55.45-1 1-1h12c.55 0 1 .45 1 1v12c0 .55-.45 1-1 1zm-4.44-6.19l-2.35 3.02-1.56-1.88c-.2-.25-.58-.24-.78.01l-1.74 2.23c-.26.33-.02.81.39.81h8.98c.41 0 .65-.47.4-.8l-2.55-3.39c-.19-.26-.59-.26-.79 0z'/%3E%3C/svg%3E"
          class="lazyload" />
      </div>
    </div>
    
    
    
  </div>
</div>

    
<div class="whoami__gutter"></div>
<hr class="hr-slash whoami-hr"/>
<section class="whoami">
  <div class="whoami__image-wrapper">
    
    
      
        <img data-src="/images/whoami/avatar.jpg" src="data:image/svg+xml,%0A%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath fill='none' d='M0 0h24v24H0V0z'/%3E%3Cpath fill='%23aaa' d='M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-1 16H6c-.55 0-1-.45-1-1V6c0-.55.45-1 1-1h12c.55 0 1 .45 1 1v12c0 .55-.45 1-1 1zm-4.44-6.19l-2.35 3.02-1.56-1.88c-.2-.25-.58-.24-.78.01l-1.74 2.23c-.26.33-.02.81.39.81h8.98c.41 0 .65-.47.4-.8l-2.55-3.39c-.19-.26-.59-.26-.79 0z'/%3E%3C/svg%3E" alt="Yang" class="lazyload whoami__image"/>
      
    
  </div>
  <div class="whoami__contents">
    <div class="whoami__written-by">
      WRITTEN BY
    </div>
    <div class="whoami__title">
      
        Yang
      
    </div>
    <div class="whoami__desc">
      
        Developer
      
    </div>
    <div class="whoami__social">
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      <a href="https://github.com/stefanji" title="github" aria-label="github">
        <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="25" height="25" viewBox="0 0 24 24" version="1.1">
<g id="surface3680">
<path fill="currentColor" d="M 10.898438 2.101562 C 6.300781 2.601562 2.601562 6.300781 2.101562 10.800781 C 1.601562 15.5 4.300781 19.699219 8.398438 21.300781 C 8.699219 21.398438 9 21.199219 9 20.800781 L 9 19.199219 C 9 19.199219 8.601562 19.300781 8.101562 19.300781 C 6.699219 19.300781 6.101562 18.101562 6 17.398438 C 5.898438 17 5.699219 16.699219 5.398438 16.398438 C 5.101562 16.300781 5 16.300781 5 16.199219 C 5 16 5.300781 16 5.398438 16 C 6 16 6.5 16.699219 6.699219 17 C 7.199219 17.800781 7.800781 18 8.101562 18 C 8.5 18 8.800781 17.898438 9 17.800781 C 9.101562 17.101562 9.398438 16.398438 10 16 C 7.699219 15.5 6 14.199219 6 12 C 6 10.898438 6.5 9.800781 7.199219 9 C 7.101562 8.800781 7 8.300781 7 7.601562 C 7 7.199219 7 6.601562 7.300781 6 C 7.300781 6 8.699219 6 10.101562 7.300781 C 10.601562 7.101562 11.300781 7 12 7 C 12.699219 7 13.398438 7.101562 14 7.300781 C 15.300781 6 16.800781 6 16.800781 6 C 17 6.601562 17 7.199219 17 7.601562 C 17 8.398438 16.898438 8.800781 16.800781 9 C 17.5 9.800781 18 10.800781 18 12 C 18 14.199219 16.300781 15.5 14 16 C 14.601562 16.5 15 17.398438 15 18.300781 L 15 20.898438 C 15 21.199219 15.300781 21.5 15.699219 21.398438 C 19.398438 19.898438 22 16.300781 22 12.101562 C 22 6.101562 16.898438 1.398438 10.898438 2.101562 Z M 10.898438 2.101562 "/>
</g>
</svg>

      </a>
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    </div>
  </div>
</section>
<hr class="hr-slash whoami-hr" />


    <section class="related">
    
    
  </section>
    <div class="grow"></div>
<nav class="pagination-single">
  
    
      <a href="https://jiyang.site/posts/2019-02-21-%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E5%85%AD%E5%A4%A7%E5%8E%9F%E5%88%99/" class="pagination-single__left">
        <div class="pagination-single__icon">
          <svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path fill="currentColor" d="M19 11H7.83l4.88-4.88c.39-.39.39-1.03 0-1.42-.39-.39-1.02-.39-1.41 0l-6.59 6.59c-.39.39-.39 1.02 0 1.41l6.59 6.59c.39.39 1.02.39 1.41 0 .39-.39.39-1.02 0-1.41L7.83 13H19c.55 0 1-.45 1-1s-.45-1-1-1z"/></svg>
        </div>
        <div class="pagination-single__left-title">面向对象六大原则</div>      
      </a>
    
    <div class="grow"></div>
    
      <a href="https://jiyang.site/posts/2019-03-15-dart%E4%B8%AD%E7%9A%84mixin/" class="pagination-single__right">      
        <div class="pagination-single__right-title">Dart中的Mixin</div>
        <div class="pagination-single__icon">
          <svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path fill="currentColor" d="M5 13h11.17l-4.88 4.88c-.39.39-.39 1.03 0 1.42.39.39 1.02.39 1.41 0l6.59-6.59c.39-.39.39-1.02 0-1.41l-6.58-6.6c-.39-.39-1.02-.39-1.41 0-.39.39-.39 1.02 0 1.41L16.17 11H5c-.55 0-1 .45-1 1s.45 1 1 1z"/></svg>
        </div>
      </a>
    
  
</nav>
    
  
    <div id="disqus_thread"></div>
<script>
  let disqus_config = function () {
    
    
    
  };
  (function () {
    if (["localhost", "127.0.0.1"].indexOf(window.location.hostname) != -1) {
      document.getElementById('disqus_thread').innerHTML = 'Disqus comments not available by default when the website is previewed locally.';
      return;
    }
    var d = document, s = d.createElement('script'); s.async = true;
    s.src = 'https://' + 'yangji' + '.disqus.com/embed.js';
  s.setAttribute('data-timestamp', +new Date());
  (d.head || d.body).appendChild(s);
  }) ();
</script>
  

    <div class="modal micromodal-slide" id="modal" aria-hidden="true">
  <div class="modal__overlay" tabindex="-1" data-micromodal-close>
    <div class="modal__container" role="dialog" aria-modal="true" aria-labelledby="modal-title">
      
      <div class="modal__content" id="modal-content">
        <div id="mySwipe" class="swipe">
          <div class="swipe-wrap">
          </div>
        </div>
      </div>

      <span class="modal__items">
        
        <span class="modal__header">
          <div class="modal__paging" title="Page Info" aria-label="Current Page">
          </div>
          <div class="modal__icon modal__toolbar modal__toolbar--close" title="Close" aria-label="Close Button" data-micromodal-close>
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26" width="25" height="25"><path fill="currentColor" d="M 21.734375 19.640625 L 19.636719 21.734375 C 19.253906 22.121094 18.628906 22.121094 18.242188 21.734375 L 13 16.496094 L 7.761719 21.734375 C 7.375 22.121094 6.746094 22.121094 6.363281 21.734375 L 4.265625 19.640625 C 3.878906 19.253906 3.878906 18.628906 4.265625 18.242188 L 9.503906 13 L 4.265625 7.761719 C 3.882813 7.371094 3.882813 6.742188 4.265625 6.363281 L 6.363281 4.265625 C 6.746094 3.878906 7.375 3.878906 7.761719 4.265625 L 13 9.507813 L 18.242188 4.265625 C 18.628906 3.878906 19.257813 3.878906 19.636719 4.265625 L 21.734375 6.359375 C 22.121094 6.746094 22.121094 7.375 21.738281 7.761719 L 16.496094 13 L 21.734375 18.242188 C 22.121094 18.628906 22.121094 19.253906 21.734375 19.640625 Z"/></svg>
          </div>
          <div class="modal__icon modal__toolbar modal__toolbar--full" title="Full Screen" aria-label="Full Screen Button">
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="25" height="25"><path fill="currentColor" d="M 5 3 C 3.9069372 3 3 3.9069372 3 5 L 3 8 A 1.0001 1.0001 0 1 0 5 8 L 5 5 L 8 5 A 1.0001 1.0001 0 1 0 8 3 L 5 3 z M 16 3 A 1.0001 1.0001 0 1 0 16 5 L 19 5 L 19 8 A 1.0001 1.0001 0 1 0 21 8 L 21 5 C 21 3.9069372 20.093063 3 19 3 L 16 3 z M 3.984375 14.986328 A 1.0001 1.0001 0 0 0 3 16 L 3 19 C 3 20.093063 3.9069372 21 5 21 L 8 21 A 1.0001 1.0001 0 1 0 8 19 L 5 19 L 5 16 A 1.0001 1.0001 0 0 0 3.984375 14.986328 z M 19.984375 14.986328 A 1.0001 1.0001 0 0 0 19 16 L 19 19 L 16 19 A 1.0001 1.0001 0 1 0 16 21 L 19 21 C 20.093063 21 21 20.093063 21 19 L 21 16 A 1.0001 1.0001 0 0 0 19.984375 14.986328 z"/></svg>
          </div>
          <div class="modal__icon modal__toolbar modal__toolbar--normal" title="Normal Screen" aria-label="Normal Screen Button">
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50" width="25" height="25"><path fill="currentColor" d="M 16.96875 4.972656 C 15.867188 4.988281 14.984375 5.894531 15 7 L 15 15 L 7 15 C 6.277344 14.988281 5.609375 15.367188 5.246094 15.992188 C 4.878906 16.613281 4.878906 17.386719 5.246094 18.007813 C 5.609375 18.632813 6.277344 19.011719 7 19 L 19 19 L 19 7 C 19.007813 6.460938 18.796875 5.941406 18.414063 5.558594 C 18.03125 5.175781 17.511719 4.964844 16.96875 4.972656 Z M 32.96875 4.972656 C 31.921875 4.988281 31.0625 5.8125 31.003906 6.859375 C 31 6.90625 31 6.953125 31 7 L 31 19 L 43 19 C 43.066406 19 43.132813 19 43.199219 18.992188 C 44.269531 18.894531 45.070313 17.972656 45.015625 16.902344 C 44.964844 15.828125 44.074219 14.988281 43 15 L 35 15 L 35 7 C 35.007813 6.460938 34.796875 5.941406 34.414063 5.558594 C 34.03125 5.175781 33.511719 4.964844 32.96875 4.972656 Z M 7 31 C 6.277344 30.988281 5.609375 31.367188 5.246094 31.992188 C 4.878906 32.613281 4.878906 33.386719 5.246094 34.007813 C 5.609375 34.632813 6.277344 35.011719 7 35 L 15 35 L 15 43 C 14.988281 43.722656 15.367188 44.390625 15.992188 44.753906 C 16.613281 45.121094 17.386719 45.121094 18.007813 44.753906 C 18.632813 44.390625 19.011719 43.722656 19 43 L 19 31 Z M 31 31 L 31 43 C 30.988281 43.722656 31.367188 44.390625 31.992188 44.753906 C 32.613281 45.121094 33.386719 45.121094 34.007813 44.753906 C 34.632813 44.390625 35.011719 43.722656 35 43 L 35 35 L 43 35 C 43.722656 35.011719 44.390625 34.632813 44.753906 34.007813 C 45.121094 33.386719 45.121094 32.613281 44.753906 31.992188 C 44.390625 31.367188 43.722656 30.988281 43 31 Z"/></svg>
          </div>
        </span>
        
        <div class="modal__icon modal__arrow modal__arrow--left" title="Arrow Left" aria-label="Arrow Left Button">
          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26" width="28" height="28"><path fill="currentColor" d="M 23.28125 11 L 10 10 L 10 6.851563 C 10 6.523438 9.839844 6.277344 9.519531 6.03125 C 9.199219 5.949219 8.878906 5.949219 8.640625 6.113281 C 5.359375 8.410156 2.238281 12.257813 2.160156 12.421875 C 2.082031 12.578125 2.007813 12.8125 2.003906 12.976563 C 2.003906 12.980469 2 12.988281 2 12.992188 C 2 13.15625 2.078125 13.402344 2.160156 13.484375 C 2.238281 13.648438 5.28125 17.507813 8.640625 19.804688 C 8.960938 19.96875 9.28125 20.050781 9.519531 19.886719 C 9.839844 19.722656 10 19.476563 10 19.148438 L 10 16 L 23.28125 15 C 23.679688 14.679688 24 13.875 24 12.992188 C 24 12.195313 23.761719 11.320313 23.28125 11 Z"/></svg>
        </div>
        
        <div class="modal__icon modal__arrow modal__arrow--right" title="Arrow Right" aria-label="Arrow Right Button">

          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26" width="28" height="28"><path fill="currentColor" d="M 2.71875 11.023438 L 16 10.023438 L 16 6.875 C 16 6.546875 16.160156 6.300781 16.480469 6.054688 C 16.800781 5.972656 17.121094 5.972656 17.359375 6.136719 C 20.640625 8.433594 23.761719 12.28125 23.839844 12.445313 C 23.917969 12.601563 23.992188 12.835938 23.996094 13 C 23.996094 13.003906 24 13.011719 24 13.015625 C 24 13.179688 23.921875 13.425781 23.839844 13.507813 C 23.761719 13.671875 20.71875 17.53125 17.359375 19.828125 C 17.039063 19.992188 16.71875 20.074219 16.480469 19.910156 C 16.160156 19.746094 16 19.5 16 19.171875 L 16 16.023438 L 2.71875 15.023438 C 2.320313 14.703125 2 13.898438 2 13.015625 C 2 12.21875 2.238281 11.34375 2.71875 11.023438 Z"/></svg>
        </div>

        <div class="modal__caption">
          <div class="modal__caption--text">
          </div>
        </div>

      </span>
    </div>
  </div>
</div>


<script defer src="/js/swipe.min.989e074dfb92ce7f57a92c1df7027f88b53c50a54fd9ad450a673a64aa91bfa4.js"></script>

<script defer src="/js/micromodal.min.de01b44b2f383056bbcaf6ee921fd385d79108ec1129afd0eb2f3f5a07e11f45.js"></script>

<script defer src="/js/helper/fadeinout.min.js"></script>

<script>
document.addEventListener('DOMContentLoaded', function () {
  
   
  var docElem = document.documentElement;

   
  function openFullscreen() {
    if (docElem.requestFullscreen) {
      docElem.requestFullscreen();
    } else if (docElem.mozRequestFullScreen) {  
      docElem.mozRequestFullScreen();
    } else if (docElem.webkitRequestFullscreen) {  
      docElem.webkitRequestFullscreen();
    } else if (docElem.msRequestFullscreen) {  
      docElem.msRequestFullscreen();
    }
  }

   
  function closeFullscreen() {
    if (document.fullscreenElement ||
      document.webkitFullscreenElement ||
      document.mozFullScreenElement) {
      if (document.exitFullscreen) {
        document.exitFullscreen();
      } else if (document.mozCancelFullScreen) {  
        document.mozCancelFullScreen();
      } else if (document.webkitExitFullscreen) {  
        document.webkitExitFullscreen();
      } else if (document.msExitFullscreen) {  
        document.msExitFullscreen();
      }
    }
  }

  var modal = document.getElementById('modal');
  var galleryContainerElem = document.querySelector('.gallery__container');
  var swipeWrapElem = document.querySelector('.swipe-wrap');
  var mySwipeElem = document.getElementById('mySwipe');
  var arrowLeftElem = document.querySelector('.modal__arrow--left');
  var arrowRightElem = document.querySelector('.modal__arrow--right');
  var closeElem = document.querySelector('.modal__toolbar--close');
  var fullElem = document.querySelector('.modal__toolbar--full');
  var normalElem = document.querySelector('.modal__toolbar--normal');
  var captionElem = document.querySelector('.modal__caption');
  var pagingElem = document.querySelector('.modal__paging');
  var itemsElem = document.querySelector('.modal__items');
  var imgTotalNum = null;
  var myFadeTimeout = null;
  var mySwipe = null;
  var keydownFunction = function (e) {
    if (e.key === 'ArrowRight') {
      if (modal && modal.classList.contains('is-open')) {
        mySwipe.next();
      }
    } else if (e.key === 'ArrowLeft') {
      if (modal && modal.classList.contains('is-open')) {
        mySwipe.prev();
      }
    }
  }

  if (galleryContainerElem) {
    imgTotalNum = galleryContainerElem.querySelectorAll('img').length;
  } else {
    galleryContainerElem = document.querySelector('.single__contents');
    imgTotalNum = galleryContainerElem.querySelectorAll('img').length;
  }

  MicroModal.init({
    onClose: function () {
      if (mySwipe) {
        mySwipe.kill();
        mySwipe = null;
        closeFullscreen();
      }
      window.removeEventListener('keydown', keydownFunction);
    },
    disableScroll: true,
    disableFocus: true,
    awaitOpenAnimation: false,
    awaitCloseAnimation: false,
    debugMode: false,
  });

  var imageLoad = function(src) {
    return new Promise(function(resolve, reject) {
      var newImg = new Image;
      newImg.onload = function() {
        resolve(newImg);
      }
      newImg.onerror = reject;
      newImg.src = src;
    });
  }

  galleryContainerElem.querySelectorAll('img').forEach(function (elem, idx) {
    elem.style.cursor = 'pointer';

    var clonedElem = elem.cloneNode(true);
    clonedElem.style.maxHeight = '100%';
    clonedElem.style.maxWidth = '100%';
    clonedElem.onclick = function (e) {
      e.stopPropagation();
    }

    var wrapper = document.createElement('div');
    wrapper.style.width = '100%';
    wrapper.style.height = '100vh';
    wrapper.setAttribute('data-micromodal-close', '');
    wrapper.onclick = function () {
      if (mySwipe) {
        mySwipe.kill();
        mySwipe = null;
      }
    }
    wrapper.onmouseenter = function () {
      clearTimeout(myFadeTimeout);
      fadeIn(itemsElem, 200);
    };
    wrapper.onmouseleave = function () {
      myFadeTimeout = setTimeout(function () {
        fadeOut(itemsElem, 200);
      }, 2500);
    }
    wrapper.ontouchstart = function() {
      fadeIn(itemsElem, 200);
    }
    wrapper.append(clonedElem);
    swipeWrapElem.append(wrapper);

    elem.addEventListener('click', async function (e) {
      MicroModal.show('modal');
      if (mySwipe) {
        mySwipe.kill();
        mySwipe = null;
      }

      var imgSrc = e.target.getAttribute('data-src') || e.target.getAttribute('src');
      var img = await imageLoad(imgSrc);
      clonedElem.style.width = img.width + 'px';
      clonedElem.style.height = img.height + 'px';
      
      
      mySwipe = new Swipe(mySwipeElem, {
        startSlide: idx,
        draggable: true,
        autoRestart: false,
        continuous: false,
        disableScroll: true,
        stopPropagation: true,
        callback: async function (index, element) {
          
          var imgElem = element.querySelector('img');
          var imgSrc = imgElem.getAttribute('data-src') || imgElem.getAttribute('src');
          var img = await imageLoad(imgSrc);
          imgElem.style.width = img.width + 'px';
          imgElem.style.height = img.height + 'px';

          
          if (captionElem && imgElem) {
            var caption = null;
            if (imgElem.getAttribute('data-caption')) {
              caption = imgElem.getAttribute('data-caption');
            } else if (imgElem.getAttribute('title')) {
              caption = imgElem.getAttribute('title');
            } else if (imgElem.getAttribute('alt')) {
              caption = imgElem.getAttribute('alt');
            } else {
              caption = imgElem.getAttribute('src');
            }

            captionElem.querySelector('.modal__caption--text').innerText = caption;
            pagingElem.innerText = (index + 1) + ' / ' + imgTotalNum;

            clearTimeout(myFadeTimeout);
            fadeIn(itemsElem, 200);
          }
        },
      });

      fadeIn(itemsElem);

      
      if (captionElem) {
        var caption = null;
        if (e.target.getAttribute('data-caption')) {
          caption = e.target.getAttribute('data-caption');
        } else if (e.target.getAttribute('title')) {
          caption = e.target.getAttribute('title');
        } else if (e.target.getAttribute('alt')) {
          caption = e.target.getAttribute('alt');
        } else {
          caption = e.target.getAttribute('src');
        }

        captionElem.querySelector('.modal__caption--text').innerText = caption;
        pagingElem.innerText = (idx + 1) + ' / ' + imgTotalNum;
      }

      if (normalElem && fullElem) {
        normalElem.style.zIndex = -1;
        normalElem.style.opacity = 0;
        fullElem.style.zIndex = 25;
        fullElem.style.opacity = 1;
      }
    });

    window.addEventListener('keydown', keydownFunction);
  });

  arrowLeftElem ?
    arrowLeftElem.addEventListener('click', function (e) {
      if (mySwipe) {
        mySwipe.prev();
      }
    }) : null;
  arrowRightElem ?
    arrowRightElem.addEventListener('click', function (e) {
      if (mySwipe) {
        mySwipe.next();
      }
    }) : null;

  closeElem ?
    closeElem.addEventListener('click', function () {
      if (mySwipe) {
        mySwipe.kill();
        mySwipe = null;
      }
      closeFullscreen();
      MicroModal.close('modal');
    }) : null;

  fullElem ?
    fullElem.addEventListener('click', function (e) {
      openFullscreen();
      if (normalElem) {
        normalElem.style.zIndex = 25;
        normalElem.style.opacity = 1;
        fullElem.style.zIndex = -1;
        fullElem.style.opacity = 0;
      }
    }) : null;

  normalElem ?
    normalElem.addEventListener('click', function (e) {
      closeFullscreen();
      if (fullElem) {
        fullElem.style.zIndex = 25;
        fullElem.style.opacity = 1;
        normalElem.style.zIndex = -1;
        normalElem.style.opacity = 0;
      }
    }) : null;
  
});
</script>

    <div class="hide">
      

<div class="search">
  <span class="icon">
    <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" fill="currentColor" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M15.5 14h-.79l-.28-.27c1.2-1.4 1.82-3.31 1.48-5.34-.47-2.78-2.79-5-5.59-5.34-4.23-.52-7.79 3.04-7.27 7.27.34 2.8 2.56 5.12 5.34 5.59 2.03.34 3.94-.28 5.34-1.48l.27.28v.79l4.25 4.25c.41.41 1.08.41 1.49 0 .41-.41.41-1.08 0-1.49L15.5 14zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/></svg>
  </span>
  <input id="search" aria-label="Site Search" class="input" type="text" placeholder="Search" autocomplete="off">
  <div id="search-results" class="dropdown">
    <div id="search-menu" class="dropdown-menu" role="menu">
    </div>
  </div>
</div>


    </div>
  </div>
</main>


<aside class="single__side main-side">
  


<section class="sidebar hide">
  <script>document.querySelector('.sidebar').classList.remove('hide')</script>
  <div class="toc__flexbox" data-position="fixed">
    <h6 class="toc__title" data-ani="true">What&#39;s on this Page</h6>
    
      <label class="switch" data-ani="true">
        <input id="toggle-toc" aria-label="Toggle TOC" type="checkbox" checked>
        <span class="slider round"></span>
      </label>
    
  </div>
  <div class="toc " data-dir="ltr" data-folding="false" data-ani="true">
    <nav id="TableOfContents">
  <ul>
    <li>
      <ul>
        <li><a href="#特别点">特别点</a></li>
        <li><a href="#特别的关键字">特别的关键字</a>
          <ul>
            <li><a href="#library-相关">library 相关</a></li>
            <li><a href="#异步编程支持">异步编程支持</a></li>
            <li><a href="#generators-中使用">Generators 中使用</a></li>
            <li><a href="#函数相关">函数相关</a></li>
            <li><a href="#类相关">类相关</a></li>
            <li><a href="#异常">异常</a></li>
            <li><a href="#其他">其他</a></li>
          </ul>
        </li>
        <li><a href="#变量">变量</a></li>
        <li><a href="#built-in-type">Built-in Type</a></li>
        <li><a href="#functions">Functions</a>
          <ul>
            <li><a href="#参数">参数</a></li>
            <li><a href="#main-函数">main 函数</a></li>
            <li><a href="#函数作为参数">函数作为参数</a></li>
            <li><a href="#匿名函数">匿名函数</a></li>
          </ul>
        </li>
        <li><a href="#operators">Operators</a></li>
        <li><a href="#class">Class</a>
          <ul>
            <li><a href="#构造函数">构造函数</a></li>
            <li><a href="#方法">方法</a>
              <ul>
                <li><a href="#实例方法">实例方法</a></li>
                <li><a href="#geter-seter">geter seter</a></li>
                <li><a href="#抽象方法-abstract-method">抽象方法 abstract method</a></li>
                <li><a href="#抽象类">抽象类</a></li>
                <li><a href="#隐式接口">隐式接口</a></li>
                <li><a href="#使用-mixin">使用 mixin</a></li>
                <li><a href="#类变量和方法">类变量和方法</a></li>
              </ul>
            </li>
          </ul>
        </li>
        <li><a href="#泛型">泛型</a></li>
        <li><a href="#异步">异步</a>
          <ul>
            <li><a href="#创建异步方法">创建异步方法</a></li>
            <li><a href="#等待-future-的结果">等待 Future 的结果</a>
              <ul>
                <li><a href="#捕获异常">捕获异常</a></li>
              </ul>
            </li>
            <li><a href="#等待-stream-的结果">等待 Stream 的结果</a></li>
          </ul>
        </li>
        <li><a href="#generators-生成器">Generators 生成器</a></li>
        <li><a href="#callable-class">Callable class</a></li>
        <li><a href="#isolates">Isolates</a></li>
        <li><a href="#typedefs-类型定义">Typedefs 类型定义</a></li>
        <li><a href="#原数据-metadata">原数据 Metadata</a></li>
      </ul>
    </li>
  </ul>
</nav>
  </div>
</section>



</aside>

<script>
  
  
  

  var enableToc = JSON.parse("true");
  var toc = JSON.parse("null");
  var tocPosition = JSON.parse("\"inner\"");
  
  var singleMainElem = document.querySelector('.single__main');
  var singleSideElem = document.querySelector('.single__side');

  enquire.register("screen and (max-width: 769px)", {
    match: function () {
      if ((enableToc || toc) && tocPosition !== "outer") {
        if (singleMainElem && singleSideElem) {
          singleMainElem.classList.remove('main-main');
          singleMainElem.classList.add('main');
          singleSideElem.classList.remove('main-side');
          singleSideElem.classList.add('hide');
        }
      } else if (tocPosition === "outer") {
        if (singleMainElem && !singleMainElem.classList.contains('main-main')) {
          singleMainElem.classList.remove('main-main');
          singleMainElem.classList.add('main');
        }
        if (singleSideElem && !singleSideElem.classList.contains('hide')) {
          singleSideElem.classList.add('hide');
        }
      }
    },
    unmatch: function () {
      if ((enableToc || toc) && tocPosition !== "outer") {
        singleMainElem.classList.remove('main');
        singleMainElem.classList.add('main-main');
        singleSideElem.classList.remove('hide');
        singleSideElem.classList.add('main-side');
      } else if (tocPosition === "outer") {
        if (singleMainElem && !singleMainElem.classList.contains('main-main')) {
          singleMainElem.classList.remove('main-main');
          singleMainElem.classList.add('main');
        }
        if (singleSideElem && !singleSideElem.classList.contains('hide')) {
          singleSideElem.classList.add('hide');
        }
      }

      var navCollapseBtn = document.querySelector('.navbar__burger');
      var navCollapse = document.getElementsByClassName('navbarm__collapse')[0];
      if (navCollapse) {
        navCollapse.setAttribute('data-open', false);
        navCollapse.style.maxHeight = 0;
        navCollapseBtn.classList.remove('is-active');
      }
      document.getElementsByClassName('navbar__menu')[0].classList.remove('is-active');
      document.getElementsByClassName('mobile-search')[0].classList.add('hide');
    },
    setup: function () { },
    deferSetup: true,
    destroy: function () { },
  });
</script>





<script defer src="/js/helper/getParents.min.js"></script>

<script defer src="/js/helper/closest.min.js"></script>

<script defer src="/js/helper/prev.min.js"></script>

<script defer src="/js/helper/prop.min.js"></script>

<script defer src="/js/helper/fadeinout.min.js"></script>

<script defer src="/js/helper/throttle.min.js"></script>



















































<script>
  'use strict';

  window.onload = function() {
    var navbar = document.querySelector('.navbar');
    var singleContentsElem = document.querySelector('.single__contents');

    
    
    
    var enableBusuanzi = JSON.parse("false");
    var busuanziPagePV = JSON.parse("true");
    
    if (enableBusuanzi && busuanziPagePV) {
      var pagePvElem = document.querySelector('#busuanzi_value_page_pv');
      pagePvElem.textContent = pagePvElem.textContent.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,");
    }    
    



    
    
    
    
    
    
    var enableToc = JSON.parse("true");
    var toc = JSON.parse("null");
    var hideToc = JSON.parse("false");
    var tocFlexbox = document.querySelector('.toc__flexbox');
    var tocFlexboxOuter = document.querySelector('.toc__flexbox--outer');
    var tocFolding = JSON.parse("false");
    
    if ((enableToc || toc) && document.querySelector('.toc')) {
      var tableOfContentsElem = document.querySelector('.toc').querySelector('#TableOfContents');

      tableOfContentsElem.onmouseenter = function() {
        if (navbar.classList.contains('scrolling')) {
          navbar.classList.remove('scrolling');
        }
      }

      tableOfContentsElem.onmouseleave = function() {
        if (!navbar.classList.contains('scrolling')) {
          navbar.classList.add('scrolling');
        }
      }

      if (false === tocFolding) {

      } else {
        tableOfContentsElem.querySelectorAll('ul') ?
          tableOfContentsElem.querySelectorAll('ul').forEach(function (rootUl) {
            rootUl.querySelectorAll('li').forEach(function (liElem) {
              liElem.querySelectorAll('ul').forEach(function (ulElem) {
                ulElem.style.display = 'none';
              });
            });
          }) : null;
      }

      if (tableOfContentsElem) {
        if (tableOfContentsElem.querySelectorAll('a').length > 0) {
          tableOfContentsElem.querySelectorAll('a').forEach(function (elem) {
            elem.addEventListener('click', function () {
              var id = elem.getAttribute('id');

              if (!navbar.classList.contains('scrolling')) {
                navbar.classList.remove('navbar--show');
                navbar.classList.remove('navbar--hide');
                navbar.classList.add('navbar--hide');
              }
              
              document.querySelector('.toc').querySelectorAll('a').forEach(function (elem) {
                elem.classList.remove('active');
              });
              elem.classList.add('active');

              var curElem = tableOfContentsElem.querySelector('[href="#' + id + '"]');
              if (curElem && curElem.nextElementSibling) {
                curElem.nextElementSibling.style.display = 'block';
              }
              if (curElem) {
                getParents(curElem, 'ul') ?
                  getParents(curElem, 'ul').forEach(function (elem) {
                    elem.style.display = 'block';
                  }) : null;
              }
            });
          });
        } else {
          if (tocFlexbox) {
            tocFlexbox.setAttribute('data-position', '');
            if (!tocFlexbox.classList.contains('hide')) {
              tocFlexbox.classList.add('hide');
            }
          }
          if (tocFlexboxOuter) {
            tocFlexboxOuter.setAttribute('data-position', '');
            if (!tocFlexboxOuter.classList.contains('hide')) {
              tocFlexboxOuter.classList.add('hide');
            }
          }
        }
      }

      
      var toggleTocElem = document.getElementById("toggle-toc");
      var visibleTocElem = document.getElementById('visible-toc');
      var tocElem = document.querySelector('.toc');
      var mainElem = document.querySelector('main');
      var sideElem = document.querySelector('side');
      var tocFlexboxElem = document.querySelector('.toc__flexbox');

      toggleTocElem ? 
      toggleTocElem.addEventListener('change', function(e) {
        if (e.target.checked) {
          if (tocElem) {
            fadeIn(tocElem, 200);
          }
          if (tocFlexboxElem) {
            tocFlexboxElem.setAttribute('data-position', 'fixed');
          }

          if (mainElem) {
            mainElem.classList.remove('main-main');
            mainElem.classList.remove('main');
            mainElem.classList.add('main-main');
          }
          if (sideElem) {
            sideElem.classList.remove('main-side');
          }
        } else {
          if (tocElem) {
            fadeOut(tocElem, 200);
          }
          if (tocFlexboxElem) {
            tocFlexboxElem.setAttribute('data-position', 'absolute');
          }

          if (mainElem) {
            mainElem.classList.remove('main-main');
            mainElem.classList.remove('main');
            mainElem.classList.add('main');
          }
          if (sideElem) {
            sideElem.classList.remove('main-side');
          }
        }
      }) : null;

      visibleTocElem ?
      visibleTocElem.addEventListener('change', function(e) {
        if (e.target.checked) {
          if (tocElem) {
            fadeIn(tocElem, 200);
          }
        } else {
          if (tocElem) {
            fadeOut(tocElem, 200);
          }
        }
      }) : null;
    }
    
    
    
    
    
    var topOffset = 120;
    var botOffset = 70;
    var handleWindowResize = function () {
      if (tocElem) {
        tocElem.style.maxHeight = (window.innerHeight - topOffset - botOffset) + 'px';
      }
    }
    var throttledWindowResize = throttle(handleWindowResize, 300);
    throttledWindowResize()

    
    window.addEventListener('resize', throttledWindowResize);
    



    
    var text, clip = new ClipboardJS('.anchor');
    var headers = singleContentsElem.querySelectorAll("h1, h2, h3, h4");

    
    var languagedir = JSON.parse("\"ltr\"");

    headers ? 
    headers.forEach(function (elem) {
      var size = parseInt(elem.tagName.substr(1), 10) * 2;
      var url = encodeURI(document.location.origin + document.location.pathname);
      var link = url + "#" + elem.getAttribute('id');
      var newElemOuter = document.createElement('span');
      newElemOuter.classList.add('anchor');
      newElemOuter.classList.add('hide');
      newElemOuter.setAttribute('data-clipboard-text', decodeURI(link));
      newElemOuter.style.position = 'relative';

      var newElemInner = document.createElement('span');
      newElemInner.style.position = 'absolute';
      newElemInner.style.top = '50%';
      newElemInner.style.left = '0.75rem';
      newElemInner.style.transform = 'translateY(-50%)';
      newElemInner.innerHTML = `
<svg fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="${32 - size}px" height="${32 - size}px"><path d="M 5.5625 0 C 4.136719 0 2.707031 0.542969 1.625 1.625 C -0.539063 3.789063 -0.539063 7.335938 1.625 9.5 L 5.28125 13.15625 C 5.667969 13.554688 6.304688 13.558594 6.703125 13.171875 C 7.101563 12.785156 7.105469 12.148438 6.71875 11.75 L 3.03125 8.0625 C 1.632813 6.664063 1.632813 4.429688 3.03125 3.03125 C 4.429688 1.632813 6.664063 1.632813 8.0625 3.03125 L 12.96875 7.9375 C 14.367188 9.335938 14.367188 11.570313 12.96875 12.96875 C 12.804688 13.132813 12.621094 13.25 12.4375 13.375 C 11.980469 13.6875 11.859375 14.308594 12.171875 14.765625 C 12.484375 15.222656 13.105469 15.34375 13.5625 15.03125 C 13.847656 14.835938 14.125 14.625 14.375 14.375 C 16.539063 12.210938 16.539063 8.664063 14.375 6.5 L 9.5 1.625 C 8.417969 0.542969 6.988281 0 5.5625 0 Z M 10.78125 8.875 C 10.738281 8.882813 10.695313 8.894531 10.65625 8.90625 C 10.507813 8.9375 10.371094 9 10.25 9.09375 C 10.039063 9.253906 9.820313 9.429688 9.625 9.625 C 7.460938 11.789063 7.460938 15.335938 9.625 17.5 L 14.5 22.375 C 16.664063 24.539063 20.210938 24.539063 22.375 22.375 C 24.539063 20.210938 24.539063 16.664063 22.375 14.5 L 18.71875 10.875 C 18.476563 10.578125 18.089844 10.441406 17.714844 10.527344 C 17.34375 10.613281 17.050781 10.90625 16.964844 11.277344 C 16.878906 11.652344 17.015625 12.039063 17.3125 12.28125 L 20.96875 15.9375 C 22.367188 17.335938 22.367188 19.570313 20.96875 20.96875 C 19.570313 22.367188 17.335938 22.367188 15.9375 20.96875 L 11.03125 16.0625 C 9.632813 14.664063 9.632813 12.429688 11.03125 11.03125 C 11.152344 10.90625 11.300781 10.820313 11.4375 10.71875 C 11.839844 10.472656 12.015625 9.976563 11.855469 9.53125 C 11.699219 9.085938 11.25 8.8125 10.78125 8.875 Z"/></svg>`;

      if (languagedir === "rtl") {
        newElemInner.style.left = '-2rem';
      } else {
        newElemInner.style.right = '-2rem';
      }

      newElemOuter.append(newElemInner);
      elem.append(newElemOuter);

      elem.addEventListener('mouseenter', function() {
        this.querySelector('.anchor').classList.remove('hide');
      });
      elem.addEventListener('mouseleave', function () {
        this.querySelector('.anchor').classList.add('hide');
      });
    }) : null;

    document.querySelectorAll('.anchor').forEach(function(elem) {
      elem.addEventListener('mouseleave', function() {
        elem.setAttribute('aria-label', null);
        elem.classList.remove('tooltipped');
        elem.classList.remove('tooltipped-s');
        elem.classList.remove('tooltipped-w');
      });
    });

    clip.on('success', function (e) {
      e.clearSelection();
      e.trigger.setAttribute('aria-label', 'Link copied to clipboard!');
      e.trigger.classList.add('tooltipped');
      e.trigger.classList.add('tooltipped-s');
    });
    // =================================================================



    
    
    var lib = JSON.parse("null");

    if (lib && lib.includes('mermaid')) {
      
      var themeVariant = localStorage.getItem('theme') || JSON.parse("\"light\"");

      if (themeVariant === "dark" || themeVariant === "hacker") {
        mermaid.initialize({ theme: 'dark' });
      } else {
        mermaid.initialize({ theme: 'default' });
      }
      
      var mermaids = [];
      [].push.apply(mermaids, document.getElementsByClassName('language-mermaid'));
      mermaids.forEach(function(elem) {
        var elemParentNode = elem.parentNode;

        if (elemParentNode !== document.body) {
          elemParentNode.parentNode.insertBefore(elem, elemParentNode);
          elemParentNode.parentNode.removeChild(elemParentNode);
        }

        var newElemWrapper = document.createElement('div');
        newElemWrapper.classList.add('mermaid');
        newElemWrapper.style.padding = '34px 4px 6px';
        newElemWrapper.innerHTML = elem.innerHTML;
        elem.replaceWith(newElemWrapper);
      });
    }
    

    

    
    if (lib && lib.includes('katex')) {
      var mathElements = document.getElementsByClassName('math');
      var options = {
        delimiters: [
          { left: "$$", right: "$$", display: true },
          { left: "\\[", right: "\\]", display: true },
          { left: "$", right: "$", display: false },
          { left: "\\(", right: "\\)", display: false }
        ],
      };

      renderMathInElement(document.querySelector('.single__contents'), options);
    }
    



    
    if (lib && lib.includes('flowchartjs')) {
      
      var options = JSON.parse("{\"arrow-end\":\"block\",\"element-color\":\"black\",\"fill\":\"white\",\"flowstate\":{\"approved\":{\"fill\":\"#58C4A3\",\"font-size\":12,\"no-text\":\"n/a\",\"yes-text\":\"APPROVED\"},\"current\":{\"fill\":\"yellow\",\"font-color\":\"red\",\"font-weight\":\"bold\"},\"future\":{\"fill\":\"#FFFF99\"},\"invalid\":{\"fill\":\"#444444\"},\"past\":{\"fill\":\"#CCCCCC\",\"font-size\":12},\"rejected\":{\"fill\":\"#C45879\",\"font-size\":12,\"no-text\":\"REJECTED\",\"yes-text\":\"n/a\"},\"request\":{\"fill\":\"blue\"}},\"font-color\":\"black\",\"font-size\":14,\"line-color\":\"black\",\"line-length\":50,\"line-width\":3,\"no-text\":\"no\",\"scale\":1,\"symbols\":{\"end\":{\"class\":\"end-element\"},\"start\":{\"element-color\":\"green\",\"fill\":\"yellow\",\"font-color\":\"red\"}},\"text-margin\":10,\"x\":0,\"y\":0,\"yes-text\":\"yes\"}");
      var jsonContent = null;

      var flowchartPrefix = "language-flowchart";
      var index = 0;
      Array.prototype.forEach.call(document.querySelectorAll("[class^=" + flowchartPrefix + "]"), function(x){
          x.style.display = 'none'
          x.parentNode.style.backgroundColor = "transparent"
          jsonContent = x.innerText;

          var node0 = document.createElement('div');
          node0.id = 'flowchart' + index;
          x.parentNode.insertBefore(node0, x);

          var diagram = flowchart.parse(jsonContent);
          diagram.drawSVG("flowchart"+index, options);

          index +=1;
      });      
    }
    

    

    
    document.querySelectorAll("mjx-container").forEach(function (x) {
      x.parentElement.classList += 'has-jax'
    });
    



    
    if (lib && lib.includes('msc')) {
      
      var options = JSON.parse("{\"theme\":\"hand\"}");
      var jsonContent = null;

      var index = 0;
      var chartPrefix = "language-msc";
      Array.prototype.forEach.call(document.querySelectorAll("[class^=" + chartPrefix + "]"), function (x) {
        x.style.display = 'none'
        x.parentNode.style.backgroundColor = "transparent"
        jsonContent = x.innerText;
        var node0 = document.createElement('div');
        node0.id = 'msc' + index;
        x.parentNode.insertBefore(node0, x);
        var diagram = Diagram.parse(jsonContent);
        diagram.drawSVG("msc" + index, options);
        index += 1;
      });
    }
    



    
    if (lib && lib.includes('chart')) {
      var borderColor = "#666";
      var bgColor = "#ddd";
      var borderWidth = 2;

      Chart.defaults.global.elements.rectangle.borderWidth = borderWidth;
      Chart.defaults.global.elements.rectangle.borderColor = borderColor;
      Chart.defaults.global.elements.rectangle.backgroundColor = bgColor;

      Chart.defaults.global.elements.line.borderWidth = borderWidth;
      Chart.defaults.global.elements.line.borderColor = borderColor;
      Chart.defaults.global.elements.line.backgroundColor = bgColor;

      Chart.defaults.global.elements.point.borderWidth = borderWidth;
      Chart.defaults.global.elements.point.borderColor = borderColor;
      Chart.defaults.global.elements.point.backgroundColor = bgColor;

      var chartPrefix = "language-chart";
      var index = 0;
      var jsonContent = null;

      Array.prototype.forEach.call(document.querySelectorAll("[class^=" + chartPrefix + "]"), function (x) {
        x.style.display = 'none'
        x.parentNode.style.backgroundColor = "transparent"
        jsonContent = x.innerText;
        var node0 = document.createElement('canvas');
        var source = null;
        node0.height = 200;
        node0.style.height = 200;
        node0.id = 'myChart' + index;
        source = JSON.parse(jsonContent);
        x.parentNode.insertBefore(node0, x);
        var ctx = document.getElementById('myChart' + index).getContext('2d');
        var myChart = new Chart(ctx, source);
        index += 1;
      });            
    }
    



    
    if (lib && lib.includes('wavedrom')) {
      var wavePrefix = "language-wave";
      var index = 0;
      var jsonContent = null;
      
      Array.prototype.forEach.call(document.querySelectorAll("[class^=" + wavePrefix + "]"), function (x) {
        x.style.display = 'none'
        x.parentNode.style.backgroundColor = "transparent"
        jsonContent = x.innerText;
        var node0 = document.createElement('div');
        var source = null;
        node0.id = 'WaveDrom_Display_' + index;
        source = JSON.parse(jsonContent);
        x.parentNode.insertBefore(node0, x);
        WaveDrom.RenderWaveForm(index, source, "WaveDrom_Display_");
        index += 1;
      });
    }
    



    
    if (lib && lib.includes('viz')) {
      var vizPrefix = "language-viz-";
      Array.prototype.forEach.call(document.querySelectorAll("[class^=" + vizPrefix + "]"), function (x) {
        x.style.display = 'none'
        x.parentNode.style.backgroundColor = "transparent"
        var engine;
        x.getAttribute("class").split(" ").forEach(function (cls) {
          if (cls.startsWith(vizPrefix)) {
            engine = cls.substr(vizPrefix.length);
          }
        });
        var viz = new Viz();
        viz.renderSVGElement(x.innerText, { engine: engine })
          .then(function (element) {
            element.style.width = "100%";
            x.parentNode.insertBefore(element, x);
          })
      });
    }
    
    
  }
</script>


            
            <footer class="footer">

    
<div class="dropdown">
  <button class="dropdown-trigger" aria-label="Select Language Button">
    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path fill="currentColor" d="M12.65 15.67c.14-.36.05-.77-.23-1.05l-2.09-2.06.03-.03c1.74-1.94 2.98-4.17 3.71-6.53h1.94c.54 0 .99-.45.99-.99v-.02c0-.54-.45-.99-.99-.99H10V3c0-.55-.45-1-1-1s-1 .45-1 1v1H1.99c-.54 0-.99.45-.99.99 0 .55.45.99.99.99h10.18C11.5 7.92 10.44 9.75 9 11.35c-.81-.89-1.49-1.86-2.06-2.88-.16-.29-.45-.47-.78-.47-.69 0-1.13.75-.79 1.35.63 1.13 1.4 2.21 2.3 3.21L3.3 16.87c-.4.39-.4 1.03 0 1.42.39.39 1.02.39 1.42 0L9 14l2.02 2.02c.51.51 1.38.32 1.63-.35zM17.5 10c-.6 0-1.14.37-1.35.94l-3.67 9.8c-.24.61.22 1.26.87 1.26.39 0 .74-.24.88-.61l.89-2.39h4.75l.9 2.39c.14.36.49.61.88.61.65 0 1.11-.65.88-1.26l-3.67-9.8c-.22-.57-.76-.94-1.36-.94zm-1.62 7l1.62-4.33L19.12 17h-3.24z"/></svg>
  </button>
  <div class="dropdown-content">
    
    
    
  </div>
</div>

    
<div class="footer__social">
  <div class="social">
    
            
    
            
    
            
    
            
    
            
    
            
    
      
      <a href="https://github.com/stefanji" title="github" aria-label="github">
        <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 24 24" version="1.1">
<g id="surface3680">
<path fill="currentColor" d="M 10.898438 2.101562 C 6.300781 2.601562 2.601562 6.300781 2.101562 10.800781 C 1.601562 15.5 4.300781 19.699219 8.398438 21.300781 C 8.699219 21.398438 9 21.199219 9 20.800781 L 9 19.199219 C 9 19.199219 8.601562 19.300781 8.101562 19.300781 C 6.699219 19.300781 6.101562 18.101562 6 17.398438 C 5.898438 17 5.699219 16.699219 5.398438 16.398438 C 5.101562 16.300781 5 16.300781 5 16.199219 C 5 16 5.300781 16 5.398438 16 C 6 16 6.5 16.699219 6.699219 17 C 7.199219 17.800781 7.800781 18 8.101562 18 C 8.5 18 8.800781 17.898438 9 17.800781 C 9.101562 17.101562 9.398438 16.398438 10 16 C 7.699219 15.5 6 14.199219 6 12 C 6 10.898438 6.5 9.800781 7.199219 9 C 7.101562 8.800781 7 8.300781 7 7.601562 C 7 7.199219 7 6.601562 7.300781 6 C 7.300781 6 8.699219 6 10.101562 7.300781 C 10.601562 7.101562 11.300781 7 12 7 C 12.699219 7 13.398438 7.101562 14 7.300781 C 15.300781 6 16.800781 6 16.800781 6 C 17 6.601562 17 7.199219 17 7.601562 C 17 8.398438 16.898438 8.800781 16.800781 9 C 17.5 9.800781 18 10.800781 18 12 C 18 14.199219 16.300781 15.5 14 16 C 14.601562 16.5 15 17.398438 15 18.300781 L 15 20.898438 C 15 21.199219 15.300781 21.5 15.699219 21.398438 C 19.398438 19.898438 22 16.300781 22 12.101562 C 22 6.101562 16.898438 1.398438 10.898438 2.101562 Z M 10.898438 2.101562 "/>
</g>
</svg>

      </a>
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
    
  
  
    
      <a href="https://jiyang.site/posts/index.xml" type="application/rss+xml" title="RSS" aria-label="RSS Feed Link">
        <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><circle fill="currentColor" cx="6.18" cy="17.82" r="2.18"/><path fill="currentColor" d="M5.59 10.23c-.84-.14-1.59.55-1.59 1.4 0 .71.53 1.28 1.23 1.4 2.92.51 5.22 2.82 5.74 5.74.12.7.69 1.23 1.4 1.23.85 0 1.54-.75 1.41-1.59-.68-4.2-3.99-7.51-8.19-8.18zm-.03-5.71C4.73 4.43 4 5.1 4 5.93c0 .73.55 1.33 1.27 1.4 6.01.6 10.79 5.38 11.39 11.39.07.73.67 1.28 1.4 1.28.84 0 1.5-.73 1.42-1.56-.73-7.34-6.57-13.19-13.92-13.92z"/></svg>
      </a>
    
  


  </div>
</div>

    
<div id="gtt">
  <div class="gtt">
    <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" d="M8.12 14.71L12 10.83l3.88 3.88c.39.39 1.02.39 1.41 0 .39-.39.39-1.02 0-1.41L12.7 8.71c-.39-.39-1.02-.39-1.41 0L6.7 13.3c-.39.39-.39 1.02 0 1.41.39.38 1.03.39 1.42 0z"/></svg>
  </div>
</div>

    <hr />

    <div class="basicflex flexwrap">
        
    </div>

    <div class="footer__poweredby">
        
        
        <p class="caption">
            
            ©2021, All Rights Reserved
            
        </p>
        

        
        <p class="caption">Powered by <a href="https://gohugo.io/" target="_blank" rel="noreferrer">Hugo</a> and the <a
                href="https://github.com/zzossig/hugo-theme-zzo" target="_blank" rel="noreferrer">Zzo theme</a></p>
        

    </div>

</footer>
        </div>
        





<div class="wrapper__right hide" data-pad="true" dir="ltr">
  <script>document.querySelector('.wrapper__right').classList.remove('hide')</script>
  
</div>

    </div>
</body>

</html>